Réaliser un objet connecté avec CircuitPython - Niveau avancé

Dans ce tutoriel, nous allons réaliser un objet connecté. Celui-ci va utiliser la connexion internet pour récupérer et afficher des informations sur des nombres que l'utilisateur choisira.

Matériel nécessaire

Pour réaliser ce projet, nous aurons besoin

  • d'une carte Adafruit M4 sous circuitPython (itsybitsy M4, metro M4 express ...)

  • d'une carte intégrant un ESP32 pour la connexion internet (comme celle-ci que j'utilise dans ce tutoriel, ou celle-la). Ces cartes coûtent moins de 5 € chacune.

  • d'un écran oled 0.96" pour l'affichage des informations

  • d'un potentiomètre et d'un bouton poussoir

  • d'une plaquette de prototypage

Principe de fonctionnement

La carte Adafruit n'est pas connectée par elle-même. Elle va donc s'appuyer sur la carte ESP32 pour réaliser la connexion internet. Cela se fait grâce à une librairie ESP32SPI développée par Adafruit à cet effet.

Ce tutoriel est écrit avec la version 4.0 beta2 de circuitPython. Il faudra aussi utiliser le dernier pack de librairies : téléchargez le bundle correspondant à la version de circuitPython utilisée et Copier le dossier lib situé dans l'archive à la racine du lecteur CIRCUITPYTHON de votre carte.

L'utilisateur va sélectionner un nombre entre 0 et 200 à l'aide du potentiomètre. Nous utiliserons donc une entrée analogique pour lire cette information. Ensuite, en pressant le bouton, la carte va se connecter sur le site http://numbersapi.com pour récupérer un fichier au format json contenant les informations sur le nombre désiré. Voir cet exemple pour 43.

Ce tutoriel nous permettra de voir la méthode pour se connecter à internet depuis circuitPython, récupérer un fichier json et en extraire les informations. Cela peut ensuite être réinvesti dans bon nombre de projets similaires (récupération de données météorologiques pour faire une station météo, etc...)

Remarque

Il est possible de réaliser ce projet exclusivement avec l'ESP32, équipé de MicroPython. Néanmoins, l'utilisation de micropython sur l'esp32 est plus délicate que celle de circuitPython sur les cartes Adafruit.

Installation du micrologiciel sur l'ESP32

Pour être utilisé comme modile wifi, l'ESP32 nécessite un micrologiciel adapté. Vous trouverez celui-ci ici

https://github.com/ladyada/CircuitPython_WiFi_Demos/tree/master/esp32program

Téléchargez le fichier NINA_W102.bin

Pour installer ce micrologiciel sur la carte ESP32, il faudra disposer de l'outil esptool.py. Le plus simple pour se le procurer est d'utiliser l'installateur de paquets pip :

sudo pip3 install esptool

Pour installer le micrologiciel, tapez la commande

esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 115200 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0 NINA_W102.bin

Vous aurez peut-être à adapter le port série sur lequel la carte ESP32 est connectée. Sous linux, c'est en général /dev/ttyUSB0.

Remarque

Cette opération n'est à faire qu'une seule fois. Ensuite la carte pourra être utilisée pour tout projet exploitant la librairie ESP32SPI d'adafruit.

Câblage

La partie délicate du câblage concerne le branchement du module ESP32. Celui-ci doit en effet être conforme à ce qui est prévu dans la librairie ESP32SPI d'adafruit. Vous n'avez pas trop de lattitude dans le choix des brochages, surtout côté ESP32.

ESP32

Adafruit M4

fonction

RST / EN

D5

reset

GND

GND

ground

3V

3V

alim 3,3V

33

D10

ready / busy

14

MOSI (MO)

SPI Master Output Slave Input

23

MISO (MI)

SPI Master Input Slave Output

5

D9

SPI CS

18

SCK

SPI SCK

Vous pouvez changer les broches D5, D9 et D10 de l'Adafruit à condition d'adapter le programme en conséquence - ces broches sont définies au début du script.

Pour l'écran, il suffit de connecter l'alimentation, puis SDA et SCL sur les broches correspondantes de la carte.

Le câblage du bouton est très simple puisqu'on utilisera le pull-up interne de la carte sur D11. Pour le potentiomètre, celui-ci sera relié à la broche A2 de la carte.

Le programme

Le programme s'appuie sur la librairie ESP32SPI d'adafruit. Celle-ci est livrée dans le pack de librairies proposé par adafruit (assurez-vous d'avoir une version à jour et qui correspond bien à votre version de circuitPython). Si votre installation de circuitPython est complète, vous n'avez donc pas à vous préoccuper du téléchargement de la librairie ESP32SPI, elle est prête à l'emploi. De même pour l'écran.

Voici donc le programme prêt à l'emploi. Il suffira juste de remplacer le SSID et le mot de passe de votre réseau Wifi dans les variables au début du programme.

1
import board
2
import busio
3
from digitalio import DigitalInOut, Direction, Pull
4
import analogio
5
import adafruit_ssd1306
6
import adafruit_bus_device
7
import adafruit_framebuf
8
from adafruit_esp32spi import adafruit_esp32spi
9
import adafruit_esp32spi.adafruit_esp32spi_requests as requests
10
11
JSON_URL1 = "http://numbersapi.com/"  # adresse du site
12
JSON_URL2 = "/math?json"              # donnees au format JSON
13
MAX_NB = 200 # valeur maxi des nb a choisir via le potentiometre
14
LLEN = 21    # longueur d'une ligne
15
LNB = 5      # nombre de lignes
16
17
WIFI_SSID = b'MON_SSID'
18
WIFI_PASS = b'********'
19
20
reset_pin = DigitalInOut(board.D4)
21
esp32_cs = DigitalInOut(board.D9)
22
esp32_ready = DigitalInOut(board.D10)
23
esp32_reset = DigitalInOut(board.D5)
24
adc = analogio.AnalogIn(board.A2)
25
bouton = DigitalInOut(board.D11)
26
bouton.direction = Direction.INPUT
27
bouton.pull = Pull.UP
28
29
i2c = busio.I2C(board.SCL, board.SDA)
30
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3c, reset=reset_pin)
31
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
32
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
33
34
requests.set_interface(esp)
35
36
if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
37
    print("ESP32 found and in idle mode")
38
print("Firmware vers.", esp.firmware_version)
39
40
oled.fill(0)
41
oled.text("Connexion Wifi",0,0,1)
42
oled.show()
43
try:
44
    esp.connect_AP(WIFI_SSID, WIFI_PASS)
45
except:
46
    oled.text("Erreur de connexion",0,10,1)
47
    oled.text("Appuyer sur RESET",0,30,1)
48
    oled.show()
49
else:
50
    oled.fill(0)
51
    texte = [""]
52
    numEcran=-1
53
    while True:
54
        oled.fill(0)
55
        nombre = str(adc.value * MAX_NB // 65535)
56
        oled.text(nombre,0,0,1)
57
        if numEcran != -1:
58
            i=0
59
            while i+numEcran*LNB < len(texte) and i<LNB :
60
                # Bidouille infame pour eviter le crash de la librairie ssd1306 sur les caracteres unicode
61
                oled.text(str(texte[i+numEcran*LNB].encode('ascii'))[2:-1],0,10+i*10,1)
62
                i+=1
63
64
        oled.show()
65
66
        if not bouton.value: # bouton presse. Logique inversee a cause du pull-up
67
            if numEcran >= 0:
68
                numEcran += 1
69
                if len(texte)<LNB*numEcran :
70
                    numEcran = -1
71
            else:
72
                # Telechargement des informations
73
                print("Recuperation infos")
74
                oled.text("......",30,0,1)
75
                oled.show()
76
                r = requests.get(JSON_URL1+nombre+JSON_URL2)
77
                reponse = r.json()
78
                print(reponse)
79
                r.close()
80
81
                # Decoupage du texte en lignes de longueur LLEN
82
                texte=[]
83
                i=0
84
                t = reponse['text']
85
                l = t[i*LLEN:(i+1)*LLEN]
86
                while l:
87
                    texte.append(l)
88
                    i+=1
89
                    l = t[i*LLEN:(i+1)*LLEN]
90
                # Affichage du texte en plusieurs ecrans
91
                numEcran=0

Complément

Vous pouvez voir que la partie requêtes sur internet est rendue très simple grâce à la librairie Adafruit. Celle-ci se résume aux commandes

Définition de l'interface : esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)

Paramétrage des requêtes via l'ESP32 : requests.set_interface(esp)

Connexion Wifi : esp.connect_AP(WIFI_SSID, WIFI_PASS)

Requête GET pour récupérer l'information : r = requests.get(__URL__)

Transformation du fichier JSON en dictionnaire pour récupérer les données : reponse = r.json()

Conclusion

Ce projet est assez complexe à mettre en œuvre, en particulier parce qu'il nécessite pas mal de matériel entre la carte adafruit M4, le module ESP et l'écran oled, même si ces composants sont facilement accessible et bon marché. Voici un aperçu du projet en fonctionnement :

Pour simplifier ce type de projet nécessitant une connexion internet, circuitPython et un affichage sur écran, Adafruit a conçu une toute nouvelle carte nommée pyPortal. Celle-ci n'est pas encore commercialisée à l'heure ou j'écris ces lignes mais semble prometteuse. Elle réunit sur une seule carte tout le montage réalisé lors de ce projet et permet donc de se focaliser uniquement sur l'aspect logiciel.