Meilleur deal à : banggood.com
Aujourd’hui, je vous propose de reprendre le code python de la station météo connectée à Jeedom réalisée avec l’écran ePaper de Waveshare et l’adapter à un écran OLED SSD1306. Comme nous allons le voir, la programmation est très similaire. On trouve ces écrans miniature de 0,96” pour moins de 5€. Choisissez de préférence un écran de type I2C qui nécessite moins de câblage (4 fils) que le bus SPI. Pour ce tutoriel, nous allons utiliser la librairie Python pour les micro-contrôleurs SSD1306 (tous les tutoriels sur le SSD1306) par Adafruit. Dans son principe, elle est très similaire au driver pour écran ePaper de Waveshare. La librairie s’occupe d’initialiser et de rafraichir l’écran. A nous de construire l’image aux dimensions de l’écran à l’aide de la librairie Python Imaging (ou son fork Pillow). Ce n’est pas la librairie la plus avancée mais elle fait le job sans trop de compétences à acquérir.
Sommaire
Matériel utilisé pour le tutoriel
Pour ce tutoriel, vous aurez besoin d’un écran OLED 0,96” de 128×64 pixels sur bus I2C ainsi que d’un Raspberry Pi (modèle 2 ou 3).
Last update was on: 29 octobre 2020 23 h 01 min
Autres résolutions et dimensions
Vérifier que Python est installé sur Raspbian
Le code de ce tutoriel a été écrit en Python 2.7. Ouvrez le Terminal ou connectez vous en SSH et exécutez la commande python –version pour vérifier que vous disposez de la bonne version. Python 2.7 est pré-installé sur Raspbian. Vous devriez obtenir quelque chose de similaire.
python --version Python 2.7.9
Câblage de l’écran OLED I2C
Installer les librairies Python Adafruit SSD1306 et PIL
La librairie Python d’Adafruit est disponible sur GitHub. On va la récupérer à l’aide de la commande git. La commande git permet de récupérer ou de synchroniser du code source sur GitHub. Commencez par installer la commande git sur Raspbian
sudo apt-get install git
Ensuite on récupère le code source et on installe la librairie. Elle sera ainsi accessible depuis n’importe quel projet Python
git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git cd Adafruit_Python_SSD1306 sudo python setup.py install
Enfin, si vous l’avez pas encore fait, installez les librairies Python-Imaging (PIL). Pour installer Pil, utilisez la commande pip. Vous aurez peut être besoin de faire précéder la commande pip d’un sudo.
sudo pip install python-pil request
Fonctionnement de la librairie Python Adafruit SSD1306
Créez un nouveau script python (nano testssd1306.py par exemple). Pour utiliser un écran OLED, on doit déjà importer les deux librairies Adafruit_GPIO et Adafruit_SSD1306. On en profite pour indiquer à Python que les caractères spéciaux seront encodés en UTF-8 au début du script (coding: UTF-8). Cela va nous permettre d’envoyer et d’afficher des caractères accentués sur l’écran OLED.
# coding: UTF-8 import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306
Pour générer l’image qui sera ensuite affichée sur l’écran OLED, on va avoir besoin des plusieurs méthodes de la librairie Python-Imaging. Image
- Image, pour créer, manipuler les images et les masques
- ImageDraw, pour dessiner du texte, des formes géométriques…
- ImageFont, pour charger des polices TrueType
Maintenant, on peut initialiser l’écran. Si votre écran OLED ne dispose pas de broche RST (Reset, indiquez 0 comme dans mon cas). La méthode Adafruit_SSD1306.SSD1306_128_64 permet de créer un objet. On doit choisir la méthode qui correspond à la résolution de l’écran utilisé. La résolution est codée ‘en dure’ dans le driver d’Adafruit. La librairie d’Adafruit propose les dimensions suivantes :
- 128×64 pixels, SSD1306_128_64
- 128×32 pixels, SSD1306_128_32
- 96×16 pixels, SSD1306_96_16
Pour ce tutoriel, j’ai utilisé un écran très habituel de 128×64 pixels sans broche de reset
# Créé un objet display - Create display object disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) # Initialise l'écran - init display disp.begin() # Efface l'écran - Clear display. disp.clear() disp.display()
Maintenant, on va récupérer la dimension de l’écran et créer un masque sur lequel on va écrire le classique “Hello World”.
width = disp.width height = disp.height image = Image.new('1', (width, height)) # On créé un objet sur lequel on va dessiner - Get drawing object to draw on image. draw = ImageDraw.Draw(image) # Charge la font par défaut - load default font font = ImageFont.load_default() # On écrit du texte dans le coin de l'écran en blanc- Draw some text draw.text((0,0), 'Hello World', font=font, fill=255)
La méthode image de la librairie Adafruit permet d’actualiser le buffer avec l’image que l’on vient de créer avec la librairie PIL. Ensuite un appel de la méthode display() permet d’actualiser l’affichage de l’écran OLED.
# Actualise l'affichage - Update display disp.image(image) disp.display()
Et voilà ce qu’on obtient.
Pour aller plus vite, collez ce code dans le script.
# coding: UTF-8 import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 import Image import ImageDraw import ImageFont RST = 0 # Créé un objet display - Create display object disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) # Initialise l'écran - init display disp.begin() # Efface l'écran - Clear display. disp.clear() disp.display() # Créé un image avec un codage des couleurs sur 1 bit (noir et blanc) # Create blank image for drawing with mode '1' for 1-bit color. width = disp.width height = disp.height image = Image.new('1', (width, height)) # On créé un objet sur lequel on va dessiner # Get drawing object to draw on image. draw = ImageDraw.Draw(image) # Charge la font par défaut - load default font font = ImageFont.load_default() # On écrit du texte - Draw some text draw.text((0,0), 'Hello World', font=font, fill=255) draw.text((0,50), 'projetsdiy.fr', font=font, fill=255) # Actualise l'affichage - Update display disp.image(image) disp.display() # Enregistre l'image en local (optionnel) - Save the image (optional) image.save("demo.bmp","bmp")
Pour pouvoir accéder au GPIO, il est nécessaire d’exécuter le code avec le droit root, il faudra donc faire précéder la commande d’un sudo comme ceci
sudo python testssd1306.py
Mini station météo connectée à Jeedom sur un Raspberry Pi
Reprenons maintenant le code de la mini station météo connectée à Jeedom développée pour l’affichage ePaper. Le principe va être très similaire. La grosse différence réside dans l’inversion des couleurs. Sur un écran ePaper, il est plus naturel d’avoir un fond blanc (bien que ce soit une question de goût plus que technique).
Avec l’écran OLED, on aura un meilleur rendu en laissant le fond noir (les pixels sont éteints). On va donc devoir soit disposer d’images blanches sur fond noir, soit inverser les couleurs en utilisant la librarie Python Imaging. C’est ce que nous allons faire ici avec la fonction ImageOps. Seul problème, la méthode ImageOps n’est pas capable de gérer des images ayant un fond transparent. je n’ai pas trouvé de fonction pour retirer la transparence de l’image (si quelqu’un connais, n’hésitez pas à utiliser les commentaires pour nous expliquer)
Je ne vais pas reprendre ici les explications sur la façon de récupérer les données météo à l’aide de l’API JSON RPC de Jeedom, je vous laisse lire l’article précédent. Vous aurez également besoin d’installer et de configurer le Widget météo de Jeedom sur votre ville.
Comme je l’ai annoncé dans l’introduction, il faut inverser les couleurs (noir/blanc). Pour cela, j’ai été obligé de supprimer la transparence (couche alpha) des pictogrammes. Pour inverser les couleurs, on dispose de la méthode ImageOps de PIL. Elle a besoin que d’un paramètre unique, l’image dont on veut inverser les couleurs.
#charge l'image - load image condition = Image.open(folder_img + prevision['condition'] + '.png') # Redimensionne l'image - Resize image condition = condition.resize((H_condition,W_condition)) # Inverse les couleurs - Invert colors condition = ImageOps.invert(condition) # Colle l'image sur le maque - past image on the mask mask.paste(condition, (0,0))
Autre remarque, pour pouvoir afficher des caractères accentués, il est nécessaire d’indiquer au début du script que les caractères sont encodés en UTF-8 avec l’option # coding: UTF-8. Ensuite si on veut pouvoir afficher des caractères spéciaux comme le degré ‘°’, il faut l’encoder manuellement lorsqu’on construit la chaine avec la méthode unicode(chaine_a_encoder,’utf-8′)
'Max.' + str(prevision['tempMax']['value']) + unicode("°C",'utf-8')
Créez un nouveau script (nano meteojeedomssd1306.py) et collez le code suivant. Modifiez les paramètres suivants dans le code
- ip_jeedom : l’adresse IP du serveur Jeedom
- Api_key : votre clé API
- Dictionnaire idCmd : changez les identifiants des différentes commandes pour celles de votre équipement météo
- modeTest : permet de générer l’image sur un ordinateur (PC Windows, Linux, Mac, Raspberry Pi) sans utiliser le GPIO et l’écran ePaper. Le script génère juste une image en sortie
- Toutes les images doivent être stockées dans le dossier image.
Téléchargez les images depuis le blog en cliquant sur ce lien. Décompressez l’archive et placez le dossier à la racine du code python. La variable folder_img permet de modifier le dossier des images.
# coding: UTF-8 import time import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 import Image import ImageOps import ImageDraw import ImageFont import requests import json import locale prevision = {} H_condition = 50 W_condition = 50 ip_jeedom = 'xxxx.xxx.xxx.xxx' Api_key = 'XXXX_JEEDOM_API_KEY_XXXX' url = "http://%s/core/api/jeeApi.php"% ( ip_jeedom) headers = {'content-type': 'application/json'} folder_img = 'images/' lever = Image.open(folder_img + 'lever.png') coucher = Image.open(folder_img + 'coucher.png') disp = Adafruit_SSD1306.SSD1306_128_64(rst = 0) disp.begin() # Clear display. disp.clear() disp.display() # Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. width = disp.width height = disp.height font = ImageFont.load_default() locale.setlocale(locale.LC_TIME,'') def updateParameter(id, method): # Toutes les méthodes json rpc Jeedom disponibles https://jeedom.github.io/core/fr_FR/jsonrpc_api#tocAnchor-1-30-2 parameters = { "jsonrpc" : "2.0", "method" : method, "params": { "apikey": Api_key, "id" : id } } return parameters def getSunTime(timestring): if len(timestring) == 3: #timestring[1:] + return timestring[0:1] + 'h' + timestring[-2:] else: return timestring[0:2] + 'h' + timestring[-2:] def findIcone(condition_id): # Toutes les conditions renvoyees par le plugin météo de Jeedom https://github.com/jeedom/plugin-weather/blob/beta/core/class/weather.class.php # Prevision d apres le code openweathermap.org # Icones Open Source https://github.com/kickstandapps/WeatherIcons # Icones température, humidité, pression atmosphérique récupérées sur https://icones8.fr if condition_id >= 200 and condition_id = 300 and condition_id = 500 and condition_id = 520 and condition_id = 600 and condition_id = 700 and condition_id = 800 and condition_id Cloud condition_id 800 => Cloud condition_id 800 => Cloud condition_id 800 => Cloud condition_id 500 => PartlySunny {'dirVent': {'unit': u'', 'value': u'70'}, 'condJ4Txt': {'unit': u'', 'value': u'Peu nuageux'}, 'city': u'Paris', 'condJ3Txt': {'unit': u'', 'value': u'Ciel d\xe9gag\xe9'}, 'vitVent': {'unit': u'km/h', 'value': 9.36}, 'pa': {'unit': u'Pa', 'value': 1026}, 'conditiontxt': {'unit': u'', 'value': u'Ciel d\xe9gag\xe9'}, 'leverSoleil': {'unit': u'', 'value': u'756'}, 'tempMin': {'unit': u'\xb0C', 'value': 3.8}, 'coucherSoleil': {'unit': u'', 'value': u'1813'}, 'condJ1Txt': {'unit': u'', 'value': u'Ciel d\xe9gag\xe9'}, 'conditionJ3': 'Cloud', 'conditionJ1': 'Cloud', 'condition': 'Cloud', 'tempMax': {'unit': u'\xb0C', 'value': 4.9}, 'tempMinJ1': {'unit': u'\xb0C', 'value': -1.9}, 'tempMinJ3': {'unit': u'\xb0C', 'value': 0.9}, 'tempMinJ2': {'unit': u'\xb0C', 'value': -3.1}, 'tempMinJ4': {'unit': u'\xb0C', 'value': -1.1}, 'conditionJ4': 'Cloud', 'humidite': {'unit': u'%', 'value': 65}, 'conditionJ2': 'PartlySunny', 'tempMaxJ4': {'unit': u'\xb0C', 'value': 1.9}, 'tempMaxJ3': {'unit': u'\xb0C', 'value': 9.1}, 'tempMaxJ2': {'unit': u'\xb0C', 'value': 6.6}, 'tempMaxJ1': {'unit': u'\xb0C', 'value': 6.5}, 'condJ2Txt': {'unit': u'', 'value': u'L\xe9g\xe8re pluie'}}
Le script enregistre également l’image générée par le script et envoyée à l’écran OLED par la librairie Adafruit. C’est assez pratique pour la mise au point le temps de recevoir l’écran. Rien ne vous empêche également de mettre au point le script sur un autre ordinateur.
Et voilà le résultat obtenu
Ainsi que sur l’écran OLED relié en I2C au Raspberry Pi 3
Avez-vous aimé cet article ?