Où sommes nous ?

Retour

Mesure de température en 1-wire avec un ESP8266 (ancien code)

Cette page contient l'ancien code permettant l'utilisation de sondes DS18B20 en utilisant la libraire DallasTemperature. Dans cet exemple, 2 sondes de même modèle sont utilisées.

Se reporter à la page pour la librairie OWBus pour la partie matériel et pour plus d'explications.

Est-ce que ca fonctionne ?

Pour vérifier que notre montage fonctionne, ce premier exemple se contentera de lister les sondes trouvées sur le bus et d'en afficher les mesures, d'une façon sale.

Les librairies

Nous aurons besoin des librairies suivantes

#include <OneWire.h>                    // Gestion du bus 1-wire
#include <DallasTemperature.h>    // Sondes ds18b20

Que nous initialiserons comme suit

#define ONE_WIRE_BUS D1           // Où est connecté le bus
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

Il est évident que le D1 peut être replacé par le port que vous souhaitez.

Pour la gestions des sondes

Pour faciliter la gestion ultérieure de nos sondes, nous allons stocker leurs adresses par le code suivant : ça évitera de devoir le redemander à chaque fois.

int nbr_sondes;    // Combien avons nous trouvé de sondes ?
DeviceAddress *sondes_adr;    // pour stocker les adresses des sondes

Et la fonction suivante permettra d'en afficher les valeurs.

String Adr2String(DeviceAddress adr){    /* Convertie une adresse en chaine */
    String str;
    for(int i=0; i<8; i++){
        if(adr[i]<16) str += '0';    // Padding si necessaire
        str += String(adr[i], HEX);
    }
    return str;
}

La fonction setup()

Première tâche : initialiser la console pour ne pas rester dans le noir

    Serial.begin(115200);    // débuging
    delay(10);    // Le temps que ça se stabilise

    Serial.print("Bus 1-wire utilisé :");
    Serial.println(ONE_WIRE_BUS);

Commençons par voir combien de sondes sont découvertes

    DS18B20.begin();

    Serial.print("Nombre de sondes :");
    Serial.println(nbr_sondes = DS18B20.getDeviceCount());

Et allouons la mémoire nécessaire pour stocker leurs adresses. On prend bien soin de vérifier que cette allocation fonctionne (on n'est pas chez m$), dans le cas contraire, exit() n'existant pas sur un microcontrôleur (eh oui, vous voulez qu'il fasse quoi en dehors de notre programme), on se contente de le placer dans un sommeil éternel ... jusqu'à son prochain reset.

    if(!(sondes_adr = (DeviceAddress *)malloc( sizeof(DeviceAddress) * nbr_sondes))){
        Serial.println("Impossible d'allouer les adresses des sondes. STOP !");
        ESP.deepSleep(0);    // On s'arrete là
    }
    Serial.println("Le stockage des adresses des sondes est alloué");

Enfin, la boucle de lecture des différentes adresses

    int duree = millis();
    for(int i=0; i<nbr_sondes; i++){
        if(DS18B20.getAddress(sondes_adr[i], i)){
            Serial.print("Sonde ");
            Serial.print(i);
            Serial.print(": ");
            Serial.println(Adr2String( sondes_adr[i] ));
           DS18B20.setResolution( sondes_adr[i], i ? 12:9);
        } else {
            Serial.print("Impossible de lire l'adresse de la Sonde ");
            Serial.println(i);
        }
        yield();
    }
    Serial.print("La lecture des sondes à durée ");
    Serial.print( millis() - duree );
    Serial.println(" milli-secondes");

À noter la fonction yield() : un seul programme tournant sur les ESP (pas de multi-tâches), sans yield() nous risquons de louper des rendez-vous importants (console, Wi-Fi) qui sont gérés en simili tâches de fond.

On notera que la 1er sonde aura une précision de 9bits contre 12 pour les suivantes. Cela influe sur la durée de conversion ... mais comme nous demandons des conversions parallèles (voir plus loin), c'est ici surtout pour voir la différence sur les valeurs reçues (évidement, j'ai vérifié que les sondes n'aient pas une trop grosse dispersion, entre 0,06 et 0,12°C dans mon cas).

et loop()

On commence par faire une demande d'acquisition de température : toutes les sondes vont se lancer dans leur conversion en parallèle ce qui nous fera gagner du temps.

void loop(){
int duree = millis();
DS18B20.requestTemperatures();
Serial.print("La demande d'aquisition a durée ");
Serial.print( millis() - duree );
Serial.println(" milli-secondes");

Attention : ces conversions demandent pas mal d'énergie, privilégier un fonctionnement séquentiel s'il y a beaucoup de sondes ce qui, je le répète, est fortement déconseillé avec ce genre de montage sans contrôleur.

Plus il y a la boucle de lecture dont le code parle de lui-même

    for(int i=0; i<nbr_sondes; i++){
        duree = millis();
        Serial.print("Température pour ");
        Serial.print(Adr2String( sondes_adr[i] ));
        Serial.print(" : ");
        Serial.print(DS18B20.getTempC( sondes_adr[i]));
        Serial.print("°C (");
        Serial.print(DS18B20.getResolution(sondes_adr[i]));
        Serial.print(" bits) en ");
        Serial.print( millis() - duree );
        Serial.println(" milli-secondes");
        yield();
    }

et enfin une tempo : prochaine mesure dans 5 minutes.

    delay(300e3);    // Prochaine mesure dans 5 minutes
}

Résultat

Et bien, ça marche très bien !

Bus 1-wire utilisé :5
Nombre de sondes :2
Le stockage des adresses des sondes est alloué
Sonde 0: 2882b25e09000015
Sonde 1: 28ddc95d0900008a
La lecture des sondes à durée 143 milli-secondes
La demande d'aquisition a durée 752 milli-secondes
Température pour 2882b25e09000015 : 20.50°C (9 bits) en 25 milli-secondes
Température pour 28ddc95d0900008a : 20.00°C (12 bits) en 26 milli-secondes
 La demande d'aquisition a durée 753 milli-secondes
Température pour 2882b25e09000015 : 20.50°C (9 bits) en 26 milli-secondes
Température pour 28ddc95d0900008a : 20.00°C (12 bits) en 25 milli-secondes

A noter que si vous obtenez une valeur de 85°C, c'est que soit vous avez un problème d'alimentation, soit que vous avez oublié de demander la conversion.

Ajout de la couche MQTT

Le réseau

On ajoute les librairies qui vont bien

#include <ESP8266WiFi.h>
#include <PubSubClient.h>    /* https://pubsubclient.knolleary.net/api.html */

et le code de connexion

void connexion_WiFi(){
    WiFi.persistent( false );    // Supprime la sauvegarde des info WiFi en Flash
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Connexion WiFi");
    WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
    while(WiFi.status() != WL_CONNECTED){
        delay(500);
        Serial.print(".");
    }

    Serial.print("ok : adresse ");
    Serial.println(WiFi.localIP());
    digitalWrite(LED_BUILTIN, HIGH);
}

J'utilise une adresse fixe pour gagner du temps (et donc de l'énergie) en ne faisant pas appel au DHCP.


MQTT

La démarche est la même avec dans un premier temps les librairies

#include <ESP8266WiFi.h>
#include <PubSubClient.h>    /* https://pubsubclient.knolleary.net/api.html */

et le code de connexion correspondant.

void Connexion_MQTT(){
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Connexion MQTT");
    while(!clientMQTT.connected()){
        if(clientMQTT.connect(MQTT_CLIENT)){
            Serial.println("connecté");
            break;
        } else {
            Serial.print("Echec, rc:");
            Serial.println(clientMQTT.state());
            delay(1000);    // Test dans 1 seconde
        }
    }
    digitalWrite(LED_BUILTIN, HIGH);
}

Dans la fonction setup(), on ne fait que définir le broker a utiliser (BROKER_HOST et BROKER_PORT sont définis dans une include dédiée contenant toutes les infos confidentielles de mon réseau)

    WiFi.config(adr_ip, adr_gateway, adr_dns);
    connexion_WiFi();
    clientMQTT.setServer(BROKER_HOST, BROKER_PORT);

Enfin, loop() devient

#define MQTT_CLIENT "TestTemp"
String MQTT_Topic("TestTemp/");
void loop(){
    if(!clientMQTT.connected())
        Connexion_MQTT();

    Serial.print("Alimentation : ");
    Serial.println(ESP.getVcc());
    clientMQTT.publish( (MQTT_Topic + "Alim").c_str(), String( ESP.getVcc() ).c_str() );
   
    int duree = millis();
    DS18B20.requestTemperatures();
    Serial.print("La demande d'aquisition a durée ");
    Serial.print( millis() - duree );
    Serial.println(" milli-secondes");

    duree = millis();    // Ainsi, nous tentons de mesurer aussi les latences dues à la conversion
    for(int i=0; i<nbr_sondes; i++){
        String adr = Adr2String( sondes_adr[i] );
        float temp;

        Serial.print("Température pour ");
        Serial.print( adr );
        Serial.print(" : ");
        Serial.print( temp = DS18B20.getTempC( sondes_adr[i]));   
        Serial.print("°C (");
        Serial.print(DS18B20.getResolution(sondes_adr[i]));
        Serial.print(" bits) en ");
        Serial.print( millis() - duree );
        Serial.println(" milli-secondes");

        clientMQTT.publish( (MQTT_Topic + adr).c_str(), String( temp ).c_str() );
        yield();
        duree = millis();
    }

    delay(300e3);    // Prochaine mesure dans 5 minutes
}

Conclusion

Le code est somme toute relativement simple. Pour une utilisation complète, seul manque le deep sleep, ça sera pour plus tard (test en cours).
La précision, 9 ou 12 bits a une influence négligeable vu que toutes les conversions ont lieu en parallèle.

Comme je le disais en introduction, hormis la question du deep sleep (inutilisé ici), on pourrait facilement créer des sondes de températures déportées à moindre coût en n'utilisant qu'un simple ESP-01.

Si cette librairie fait très bien son boulo, j'ai créé OWBus car DallasTemperature ne prend pas en compte les DS28EA00 et encore moins les puces d'autres types (PIOs ...). Du coup, mes projets se retrouvaient avec pas mal de redondances. Grâce à OWBus, tout ce qui est mutualisable l'est, ce qui rend le code à la fois plus cohérent, mais aussi le binaire plus petit.


Visitez :
La liste de nos voyages
Nos sorties Ski et rando
Copyright Laurent Faillie 2001-2024
N'oubliez pas d'entrer le mot de passe pour voir aussi les photos perso.
Contactez moi si vous souhaitez réutiliser ces photos et pour les obtenir avec une plus grande résolution.
Visites durant les 7 derniers jours Nombre de visites au total.

Vous pouvez laissez un commentaire sur cette page.