Un couple d'enfer : ESP8266 et DS18B20, un petit objet connecté à quelques euros qui mesure la température et la transmet par Wifi
Nous avons parlé de l'ESP8266 propulsé par micropython dans le billet précent. Parmi la multitude d'application possible, nous allons voir aujourd'hui comment coupler l'ESP8266 à une sonde DS18B20 pour relever périodiquement la température d'une pièce et transférer la valeur en Wifi à une base InfluxDB.
Principe
Nous parlons ici de mesure de température dans un lieu de vie : une prise de température toutes les 10 minutes est suffisante. Nous allons dès lors mettre en place le fonctionnement suivant pour l'ESP8266 :
- allumage, mise en route du Wifi, connexion au Wifi local
- mesure à 10 reprises de la température
- suppression des 2 valeurs extrêmes supérieures et des 2 valeurs extrêmes inférieures
- moyenne des 6 valeurs restantes
- envoi de la valeur à une base de données InfluxDB au moyen d'une requête POST
- mise en sommeil de l'ESP8266 pour 10 minutes
A la sortie de la mise en sommeil le cycle recommence.
En outre, un minuteur logiciel provoquera un redémarrage de l'ESP8266 s'il est bloqué 2 minutes sans arriver au bout de son cycle.
Branchements
Rien de sorcier : on alimente la sonde 1-wire DS18B20 en 3.3V (comme l'ESP8266), on en relie les masses et on place le pin de données de la sonde 1-wire sur un GPIO adéquat de l'ESP8266. Il ne faudra pas oublier la résistance de 4.7 kOhms entre le pin Vin et le pin Data de la sonde ! Et pour permettre la sortie du sommeil, il faudra relier le pin RESET (RST) de l'ESP8266 avec le GPIO 16 (celui de l'alarme RTC).
Code sur l'ESP8266
Nous allons placer le code ci-dessous dans le fichier main.py qui sera ensuite envoyé sur l'ESP8266 à l'aide des outils évoqués dans le billet précent :
./webrepl_cli.py /path/to/main.py 192.168.4.1:/
Le code intégral, fortement commenté, est là :
import socket import time import machine #pour accéder aux GPIOs import onewire, ds18x20 #pour lire la sonde 1-wire import urequests #pour envoyer la requête POST from machine import Timer #Faire flasher i fois la petite LED bleue de la puce ESP8266 def do_flashes(i): if i<1: i=1 pin = machine.Pin(2, machine.Pin.OUT) for z in range(0,i): time.sleep_ms(250) pin.value(not pin.value()) time.sleep_ms(250) pin.value(not pin.value()) pin.value(1) #On s'assure que la LED finit dans l'état "éteint" #Se connecter au Wifi local def do_connect(): import network sta_if = network.WLAN(network.STA_IF) if not sta_if.isconnected(): print('connecting to network...') sta_if.active(True) sta_if.connect('SSID', 'password') #Remplacer le nom du SSID et le mot de passe de connexion while not sta_if.isconnected(): pass print('network config:', sta_if.ifconfig()) #On imprime l'IP de la puce une fois connectée, pratique pour déboguer sur le port série do_flashes(4) #Effectuer une requête POST sur une URL InfluxDB (ou autre) def http_post(data): url = 'https://path.to.influx.db/write?db=dbname' data = ("temperature,tag1=x1,tag2=x2 value=%s" % (str(data))) resp = urequests.post(url, data=data) #Effectuer une mesure sur le GPIO 4 def do_ds18b20(): dat = machine.Pin(4) ds = ds18x20.DS18X20(onewire.OneWire(dat)) #On crée l'objet OneWire roms = ds.scan() #On scanne le bus pour trouver toutes les sondes print('found devices:', roms) #On mesure 10 fois la température if len(roms)>0: templist = [] for i in range(10): ds.convert_temp() time.sleep_ms(1000) #On attend 1 seconde entre chaque prise de mesure pour laisser le temps à la sonde de se réinitialiser temp = ds.read_temp(roms[0]) templist.append(temp) templist.remove(max(templist)) #On supprime les valeurs extrêmes templist.remove(max(templist)) templist.remove(min(templist)) templist.remove(min(templist)) sum_of_temps = 0 for temp in templist: sum_of_temps = sum_of_temps + temp final_temp = sum_of_temps/6 print('Final temp: ', final_temp) return final_temp #Redémarre l'ESP8266, "machine.reset" est équivalent à un redémarrage électrique def force_reset(): print("Machine inactive for too long, this is not normal, rebooting!") machine.reset() #Regarde si l'ESP8266 se réveille d'un sommeil profond (et non d'un (re)démarrage électrique) if machine.reset_cause() == machine.DEEPSLEEP_RESET: print('Woke from a deep sleep') #On active le minuteur qui provoque le redémarrage dans 2 minutes tim = Timer(-1) tim.init(period=120000, mode=Timer.ONE_SHOT, callback=lambda t:force_reset()) do_flashes(2) #On signale le démarrage du travail par 2 clignotements do_connect() #Connexion au Wifi time.sleep_ms(2000) #On attend 2 secondes temp = do_ds18b20() #On mesure la température http_post(temp) #On l'envoie sur InfluxDB print('set RTC alarm to wake up later') rtc = machine.RTC() rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) #On configure RTC.ALARM0 pour être capable de re-démarrer le périphérique rtc.alarm(rtc.ALARM0, 600000) # Après 600 secondes RTC.ALARM0 redémarrera la machine ! #Petit compte à rebours, pratique pour l'interrompre par Ctrl+C, quand l'on veut se connecter à l'ESP8266 pour en modifier le comportement print('deep sleep in 20 seconds') time.sleep_ms(15000) print('deep sleep in 5 seconds') time.sleep_ms(2000) print('deep sleep in 3 seconds') time.sleep_ms(1000) print('deep sleep in 2 seconds') time.sleep_ms(2000) print('deep sleep in 1 seconds') time.sleep_ms(1000) print('deep sleep now! waking up in 600 seconds') machine.deepsleep()
Et voilà une petite sonde qui prend la température toutes les 10 minutes.
Consommation ?
Un petit test rapide a montré que mon ESP8266 monté sur un kit de développement NodeMCU v1.0 (je pressens que la consommation serait moindre sans le kit de développement) :
- demande ~100 mA lors des périodes de fonctionnement
- demande <~10 mA lors de la phase de sommeil
C'est à creuser plus finement mais cela donne déjà quelques ordres de grandeur.