[WIP] Le Newbie et sa station météo IoT - RPi Zero W

Bonjour !

Je me présente rapidement avant d’entrer dans la supplication :smiley: J’ai 27 ans, je suis infographiste auto-entrepreneur et co-gérant d’une société de gestion technique événementielle, donc autant dire que je suis plutôt du côté hardware de la force… Si je me débrouille bien en maitrise des logiciels, je n’ai en revanche aucune base en codage si ce n’est les logiques simples (if then while or …etc) que j’utilise dans certains soft. Ah si, j’ai fait du HTML et CSS à la Fac :sunglasses: :joy:

En mai dernier je me suis lancé dans l’inconnu avec un projet en tête, celui de réaliser une sonde météo avec affichage en temps réel et une liaison WiFi avec gestion graphique des températures et de l’humidité via ThingSpeak ! L’idée était de pouvoir afficher différentes infos sur l’écran, et de passer de l’une à l’autre en basculant le bouzin, à l’aide donc d’un tilt-switch (par exemple : info 1 = Temp + HR + Heure, info 2 = Graph dernières 24h, info 3 = prévisions météo 5j)

Le matos que j’ai acheté (en avril) :

  • Rasp Pi Zero Wifi
  • Sonde température DS18B20
  • Sonde humidité (et température) DHT22
  • Un breadboard pour vérifier mon montage

J’ai donc assemblé mes 2 sondes en fouinant sur internet pour savoir sur quel port brancher, téléchargé les librairies correspondantes (c’est l’équivalent de drivers pour Raspberry ?)
Ensuite j’ai trouvé différents bouts de codes que j’ai arrangé à ma sauce afin de récupérer les 2 données de température, d’en faire une moyenne (tmoyenne) et d’afficher cette valeur avec l’humidité relative :

Code Temp

import sys
import Adafruit_DHT
import time

tempfile = open(« /sys/bus/w1/devices/28-031652910aff/w1_slave »)
thetext = tempfile.read()
tempfile.close()
tempdata = thetext.split(« \n »)[1].split(" ")[9]
temperature2 = float(tempdata[2:])
temperature2 = temperature2 / 1000

sensor = Adafruit_DHT.AM2302
pin = 5
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

tmoyenne = (temperature+temperature2*2)/3

print(‹ Temperature Moyenne={0:0.1f}*C Humidite={1:0.1f}% ›.format(tmoyenne, humidity))

Bon j’ai passé une journée entière à faire ça, mais j’étais super content car ça marchais impecc !
Je suis ensuite passé à l’étape IoT…pareil, bout de code adapté :

Code IoT

import sys
import Adafruit_DHT
from time import sleep
import urllib2

myAPI = « touchezpasàmonserveur »

def getSensorData():
tempfile = open(« /sys/bus/w1/devices/28-031652910aff/w1_slave »)
thetext = tempfile.read()
tempfile.close()
tempdata = thetext.split(« \n »)[1].split(" ")[9]
temperature2 = float(tempdata[2:])
temperature2 = temperature2 / 1000

sensor = Adafruit_DHT.AM2302
pin = 5
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

tmoyenne = (temperature+temperature2*2)/3

T = tmoyenne
RH = humidity

return (str(RH), str(T))

def main():
print ‹ starting… ›
baseURL = ‹ https://api.thingspeak.com/update?api_key=%s › % myAPI

while True:
try:
RH, T = getSensorData()
f = urllib2.urlopen(baseURL +
« &field1=%s&field2=%s » % (RH, T))
print f.read()
f.close()
sleep(60)
except:
print ‹ exiting. ›
break

call main

if name == ‹ main ›:
main()

Cool, j’obtiens 2 belles coubres sur thingspeak !

J’ai ensuite eu un peu moins de temps et j’ai totalement laissé le projet de côté…pour reprendre il y a quelques jours en achetant l’écran et le switch.

Voici mon bout de code pour le tilt-switch (trouvé sur Sunfounder) :

Code Tilt-switch

#!/usr/bin/env python
import RPi.GPIO as GPIO

TiltPin = 17

def setup():
GPIO.setmode(GPIO.BCM)
GPIO.setup(TiltPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(TiltPin, GPIO.BOTH, callback=detect, bouncetime=1000)

def Print(x):
if x == 1:
print ’ ***’
print ’ 1
print ’ ***’

def detect(chn):
Print(GPIO.input(TiltPin))

def loop():
while True:
pass

def destroy():
GPIO.cleanup() # Release resource

if name == ‹ main ›: # Program start from here
setup()
try:
loop()
except KeyboardInterrupt: # When ‹ Ctrl+C › is pressed, the child program destroy() will be executed.
destroy()

Si je tilt mon projet, j’obtiens donc 1, c’est parfait je ne veux pas de valeur différente pour 0 ou 1 (LOW ou HIGH). J’ai supposé que le bouncetime représentait le temps pendant lequel, après un tilt, le Pin du Tilt-switch ne serait plus « observé » par la RPi… Donc j’ai mis 1000, pour avoir un temps mort de 1sec (ça à l’air de coller, je me trompe ?).

L’idée maintenant c’est qu’à chaque tilt, j’avance dans une liste d’éléments…car à terme, quand j’aurai défini mes différents affichages, je pourrai les réunir en une liste d’éléments non ?
Si je dis que :
A = Affichage de la Température + Heure
B = Affichage de l’HR + Heure
C = Affichage de Tmoyenne + HR

Et que je crée une liste : liste = [A,B,C]
Il faudrait que je puisse switcher de l’une à l’autre en « tiltant » la boite.

Il me manque donc la fonction qui découle de 'if x == 1" alors tu passe à l’affichage suivant… Itération ? Générateur ?

Ensuite j’aurai vraiment besoin d’aide au moment de relier l’écran à la RPi, car si je comprends bien l’écran occuperai tout le GPIO… Alors comment conserver mes branchements avec les 2 sondes et le tilt-switch ? J’aimerai trouver une solution de câblage propre (j’utilise des fil de breadboard) pour le modèle final
Voici mon câblage actuel :


Dans le genre bombe artisanale on est bien :mouarf:

Thanks ! et merci d’avance pour vos contributions

PS : Désolé pour le format des codes il n’y a pas de balises adaptées ?

Aujourd’hui j’ai débranché mes deux sondes et mon tilt-switch pour tester l’écran !

Je suis assez content de moi, j’ai compris quelques notions pour discuter avec l’écran (dessiner des formes, afficher des images, du texte, le rafraichissement partiel pour afficher les données en temps réel).

Voici le code :

Code e-paper

import epd2in13
import time
import Image
import ImageDraw
import ImageFont

def clear():
epd = epd2in13.EPD()
epd.init(epd.lut_full_update)

image = Image.new(‹ 1 ›, (epd2in13.EPD_HEIGHT, epd2in13.EPD_WIDTH), 255) # 255: clear the frame
draw = ImageDraw.Draw(image)
font = ImageFont.truetype(’/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf’, 25)

epd.clear_frame_memory(0xFF)
epd.set_frame_memory(image.rotate(-90), 0, 0)
epd.display_frame()

epd.delay_ms(200)

def main():
epd = epd2in13.EPD()
epd.init(epd.lut_partial_update)

#image = Image.new(‹ 1 ›, (epd2in13.EPD_HEIGHT, epd2in13.EPD_WIDTH), 255) # 255: clear the frame

time_image = Image.new(‹ 1 ›, (epd2in13.EPD_HEIGHT, epd2in13.EPD_WIDTH), 255)
draw = ImageDraw.Draw(time_image)
time_font1 = ImageFont.truetype(’/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf’, 40)
temp_font = ImageFont.truetype(’/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf’, 28)
epd.set_frame_memory(time_image.rotate(-90), 0, 0)
epd.display_frame()
draw.line((15, 60, 235, 60), fill = 0)
draw.line((15, 61, 235, 61), fill = 0)
draw.line((15, 62, 235, 62), fill = 0)
draw.line((134, 63, 134, 110), fill = 0)
draw.line((135, 63, 135, 110), fill = 0)
draw.line((136, 63, 136, 110), fill = 0)

while (True):
draw.rectangle((25, 8, (225, 59)), fill = 255)
draw.text((30, 15), time.strftime(’%H:%M:%S’), font = time_font1, fill = 0)
draw.text((15, 75), ‹ –,- ›+chr(176)+‹ C ›, font = temp_font, fill = 0)
draw.text((150, 75), ‹ –,-% ›, font = temp_font, fill = 0)
epd.set_frame_memory(time_image.rotate(-90), 0, 0)
epd.display_frame()

if name == ‹ main ›:
clear()
main()

Il fait appel à 2 autres scripts python qui s’occupent de définir les normes de l’écran (résolution etc) de ce que j’ai pu comprendre… (« epd2in13.py » et « epdif.py »)

La première partie que j’ai appelé « clear() », permet de remettre à zéro l’écran, ensuite on passe à « main() » pour définir l’image, puis les lignes dessinées pour former ma 1ère interface. Ensuite le script qui tourne en boucle au moment d’afficher l’heure. On affiche un rectangle blanc en dessous du texte pour nettoyer entre chaque seconde et boum !

2 petits pb cependant :

  1. Dans la doc de l’écran, il est dit que le temps de rafraîchissement (partiel) est de 0,3sec. Or, mon heure s’actualise plutôt en 1,5sec je dirais… Est-ce dû à la taille de la zone à rafraîchir ? Comment améliorer ça ?

  2. L’utilisation du CPU de ma RPi oscille entre 70 et 100% ! Problème avec mon script ?

Question bonus : Est-ce que la solution pour cabler l’écran + les sondes serait pas d’avoir une carte qui dubplique le GPIO ?
Dans ce genre là :

U-geek-Original-Unassembled-Double-GPIO-Adapter-for-Raspberry-Pi-2-A-B-Zero-Transfer-GPIO
Google 1er lien

Thanks :blush:

magnifique !

je t’invite a continuer ce question reponse solo qui est magnifique, je suis sur que beaucoup t’ont deja lu !

Laches rien

Hello, merci pour ton commentaire :slight_smile:
C’est un question-réponse sans en être un, j’avance dans le projet tout seul mais étant donné que je découvre, j’ai besoin de tous les conseils possible ! Et chaque avancée amène d’autres questions…bon le seul problème c’est que je suis un peu long à lire et ça doit en rebuter quelques uns, mais j’essaie d’être exhaustif.

Là par exemple je bloque un peu sur comment assembler tous les éléments de manière propre. Une fois que j’aurai compris ça, je pourrai bosser sur l’affichage des données de mes sondes sur l’écran e-paper.

Et puis je me dis que si quelqu’un à l’idée de faire la même chose, il pourra trouver des pistes ici.

c’est mon gros probleme aussi ce que je qualifie d’intégration
mon pti doigt me dit que le pere noel va offrir un stylo 3D a ma fille xD
ca sera un début pour tenter de « coller » proprement des éléments petits, mais je pense qu’a la fin,
soit on est un bon bricoleur et on a tous les outils, soit ca passera par des impressions 3D ^^

mais vu tes premiers rendus, je suis sur que tu va trouver une solution simple sous peu :slight_smile:

Bah disons que c’est surtout au niveau du câblage que je ne suis pas calé… je découvre la programmation Python, et l’électronique en même temps.

Après pour le boitier, j’ai la chance d’avoir justement une imprimante 3D et d’avoir les compétences pour modéliser ce que je veux. Je suis sur la plateforme 3DHubs, si tu veux que je t’imprime des pièces pour quelques euros :stuck_out_tongue_winking_eye:

Mise à jour du jour :smile: :
06

J’ai pu intégrer des données météo de OpenWeatherMap ! avec un délai de rafraichissement de 1min pour la RPi ne travaille qu’une seconde par minute. Les données météo provenant du site elles, ne sont actualisées qu’une fois toute les 2h environ.

J’ai créé des pictogrammes météo qui s’actualisent en fonction des données reçues selon le code utilisé par le site !

Résumé

weather = requests.get(« LIEN DE MON API SUR OPENWEATHERMAP »)
data = weather.json()
icon = data[‹ weather ›][0][‹ icon ›] #Ici je récupère le code correspondant au pictogramme météo
icon_img = ‹ /home/pi/e-paper/python/icons ›+icon+’.jpg’ #Et je viens récupérer mon picto perso correspondant
weather_icon = Image.open(icon_img)

epd.set_frame_memory(weather_icon.rotate(-90), 72, 164) #Et je l’affiche !

J’ai beau chercher sur les internets…quelqu’un saurait comment déplacer l’ancrage d’un texte que l’on affiche sur un écran e-paper !? J’aimerai placer mon texte aux coordonnées (x, y) mais je veux que le point qui correspond à ces coordonnées se situe au centre du texte. Comme ça, si le texte s’actualise avec un caractère supplémentaire, au lieu de bouffer plus d’espace à droite, ça sera réparti des deux côtés.

Pour l’affichage j’utilise :

    draw.text((25, 110), 'Mon texte', font = font_1, fill = 255)

J’ai trouvé un argument " anchor ", mais je ne comprends pas comment il fonctionne…