Micropython: ESP32 ESP-Now Communication bidirectionnelle

Micropython: ESP32 ESP-Now Communication bidirectionnelle

Apprenez à établir une communication bidirectionnelle entre deux planches ESP32 à l’aide du protocole de communication ESP-Now. Tout d’abord, nous allons tester un exemple simple pour vous montrer comment implémenter une communication bidirectionnelle. Enfin, nous allons construire un projet plus complexe, dans lequel nous échangeons des lectures de capteurs entre les cartes et affichons les résultats sur un écran OLED.

Micropython: ESP32 ESP-Now Communication bidirectionnelle

Utiliser Arduino IDE? Suivez ce tutoriel à la place: ESP-Now Communication bidirectionnelle entre les cartes ESP32.

Table des matières

Dans ce tutoriel, nous couvrirons les sujets suivants:

Prérequis – Firmware Micropython

Pour suivre ce didacticiel, vous avez besoin de micro-firmware Micropython installé sur vos cartes ESP32 ou ESP8266. Vous avez également besoin d’un IDE pour écrire et télécharger le code sur votre carte. Nous suggérons d’utiliser Thonny IDE:

Nouveau sur Micropython? Consultez notre ebook: Micropython Programming avec ESP32 et ESP8266 Ebook (2e édition)

Présentation ESP-NOW

ESP-Now est un protocole de communication sans fil développé par ESPRESSIF qui permet à plusieurs cartes ESP32 ou ESP8266 d’échanger de petites quantités de données sans utiliser Wi-Fi ou Bluetooth. ESP-Now ne nécessite pas de connexion Wi-Fi complète (bien que le contrôleur Wi-Fi doit être activé), ce qui le rend idéal pour les applications de faible puissance et de faible latence comme les réseaux de capteurs, les télécommandes ou l’échange de données entre les cartes.

ESP-NOW - logo ESP32

ESP-Now utilise un modèle de communication sans connexion, ce qui signifie que les périphériques peuvent envoyer et recevoir des données sans se connecter à un routeur ou configurer un point d’accès (contrairement à la communication HTTP entre les cartes). Il prend en charge unicast (envoyer des données à un appareil spécifique à l’aide de son adresse MAC) et diffuser (envoyer des données à tous les appareils à l’aide d’une adresse MAC diffusée).

Nouveau sur ESP-NOW? Lisez notre guide de démarrage pour Micropython en utilisant ESP-Now avec ESP32.

ESP32: obtenir une adresse MAC à la carte

Pour communiquer via ESP-Now, vous devez connaître l’adresse MAC de vos conseils. Pour obtenir l’adresse MAC de votre carte, vous pouvez copier le code suivant sur Thonny IDE et l’exécuter sur votre carte.

# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp-now-esp32/
 
import network

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

# Get MAC address (returns bytes)
mac = wlan.config('mac')

# Convert to human-readable format
mac_address=":".join('%02x' % b for b in mac)

print("MAC Address:", mac_address)

Afficher le code brut

Après avoir exécuté le code, il devrait imprimer l’adresse MAC de la carte sur le shell.

Thonny IDE - Obtenez l'adresse MAC de la carte ESP32 - Micropython

Nous vous recommandons d’ajouter une étiquette ou un autocollant à chaque carte afin que vous puissiez les identifier clairement.

Deux planches ESP32 avec une étiquette avec leurs adresses MAC

Nous utiliserons une carte ESP32 DOIT V1 et un Devkitc ESP32 S3, mais cela devrait être compatible avec n’importe quel modèle ESP32.

Communication bidirectionnelle ESP-Now entre deux planches ESP32 (Micropython)

Dans cette section, nous vous montrerons un exemple de base sur la façon d’échanger des messages simples entre les cartes ESP32 à l’aide du protocole de communication ESP-Now. Chaque carte est en même temps un récepteur et un émetteur, nous pouvons donc les appeler émetteurs-récepteurs.

Il existe deux bibliothèques Micropython ESP-Now incluses par défaut maintenant dans les versions de firmware MicropyThon actuelles: ESPNow et Aioespnow. Nous utiliserons l’Aioespnow, qui est la version asynchrone de la bibliothèque ESPNow.

ESP-now communication bidirectionnelle entre deux planches ESP32

Copiez le code suivant sur Thonny IDE.

# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-esp-now-two-way/

import network
import aioespnow
import asyncio
import time

# Initialize Wi-Fi in station mode
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.config(channel=1)  # Set channel explicitly if packets are not received
sta.disconnect()

# Initialize AIOESPNow
e = aioespnow.AIOESPNow()
try:
    e.active(True)
except OSError as err:
    print("Failed to initialize AIOESPNow:", err)
    raise

# Peer MAC address (replace with the actual MAC of the other board)
peer_mac = b'\xff\xff\xff\xff\xff\xff'  # Example peer MAC for unicast

# Add peer for unicast reliability
try:
    e.add_peer(peer_mac)
except OSError as err:
    print("Failed to add peer:", err)
    raise

# Stats tracking
last_stats_time = time.time()
stats_interval = 10  # Print stats every 10 seconds

# Async function to send messages
async def send_messages(e, peer):
    message_count = 0
    while True:
        try:
            message = f"Hello from ESP32 #{message_count}"
            if await e.asend(peer, message, sync=True):
                print(f"Sent message: {message}")
            else:
                print("Failed to send message")
            message_count += 1
            await asyncio.sleep(1)  # Send every 1 second
        except OSError as err:
            print("Send error:", err)
            await asyncio.sleep(5)

# Async function to receive messages
async def receive_messages(e):
    while True:
        try:
            async for mac, msg in e:
                print(f"Received from {mac.hex()}: {msg.decode()}")
        except OSError as err:
            print("Receive error:", err)
            await asyncio.sleep(5)

# Async function to print stats periodically
async def print_stats(e):
    global last_stats_time
    while True:
        if time.time() - last_stats_time >= stats_interval:
            stats = e.stats()
            print("\nESP-NOW Statistics:")
            print(f"  Packets Sent: {stats[0]}")
            print(f"  Packets Delivered: {stats[1]}")
            print(f"  Packets Dropped (TX): {stats[2]}")
            print(f"  Packets Received: {stats[3]}")
            print(f"  Packets Dropped (RX): {stats[4]}")
            last_stats_time = time.time()
        await asyncio.sleep(1)  # Check every second

# Main async function
async def main(e, peer):
    # Run send, receive, and stats tasks concurrently
    await asyncio.gather(send_messages(e, peer), receive_messages(e), print_stats(e))

# Run the async program
try:
    asyncio.run(main(e, peer_mac))
except KeyboardInterrupt:
    print("Stopping transceiver...")
    e.active(False)
    sta.active(False)

Afficher le code brut

Ce code définit la carte ESP32 en tant que récepteur ESP-Now et émetteur. Dans le code, vous devez insérer l’adresse MAC de la carte à laquelle vous souhaitez envoyer des données.

Par exemple, si l’adresse MAC de la carte du récepteur est de 30: AE: A4: F6: 7d: 4c. Vous devez le convertir au format octets comme suit:

  • 30: ae: a4: f6: 7d: 4c »b ‘\ x30 \ xae \ xa4 \ xf6 \ x7d \ x4c’
# Peer MAC address
receiver_mac = b'\x30\xae\xa4\xf6\x7d\x4c'

Téléchargez ce code sur les deux cartes, mais ajustez l’adresse MAC.

Comment fonctionne le code?

Pour mieux comprendre ce code, nous vous recommandons de vous familiariser avec la programmation asynchrone Micropython en premier. Vous pouvez lire le guide suivant:

Modules d’importation

Tout d’abord, importez les modules requis.

import network
import aioespnow
import asyncio
import time

Initialiser l’interface Wi-Fi

Ensuite, nous devons initialiser le Wi-Fi (même si nous ne l’utilisons pas) pour utiliser ESP-Now. Nous pouvons utiliser la station (STA_IF) ou le mode Point d’accès (AP_IF).

# Initialize Wi-Fi in station mode
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.config(channel=1)  # Set channel 
sta.disconnect()

Initialiser ESP-now

Ensuite, nous pouvons initialiser ESP-Now. Tout d’abord, créez une instance aioespnow appelée e. Puis activez-le en utilisant la méthode active () et en passant la valeur vraie en tant qu’argument.

# Initialize AIOESPNow
e = aioespnow.AIOESPNow()
try:
    e.active(True)
    print("AIOESPNow initialized")
except OSError as err:
    print("Failed to initialize AIOESPNow:", err)
    raise

Nous activons ESP-NOW à l’intérieur d’un essai et sauf des instructions afin que nous puissions prendre des erreurs en cas d’échec de l’initialisation.

Ajouter un pair ESP-now

Insérez l’adresse MAC par les pairs (l’adresse MAC de la carte à laquelle vous souhaitez envoyer des données).

# Receiver MAC address (the board you want to send data to)
peer_mac = b'\x68\xb6\xb3\x22\x9e\x60'

Ensuite, nous pouvons ajouter l’adresse MAC du récepteur en tant que pair à l’aide de la méthode add_peer ().

try:
    e.add_peer(peer_mac)
except OSError as err:
    print("Failed to add peer:", err)
    raise

Fonction pour envoyer des messages ESP-Now

La fonction suivante envoie des messages ESP-Now au pair. Passez comme argument l’instance ESP-Now E et le pair. À titre d’exemple, nous enverrons un message Hello de ESP32 suivi d’un compteur. Nous envoyons un nouveau message à chaque seconde.

# Async function to send messages
async def send_messages(e, peer):
    message_count = 0
    while True:
        try:
            message = f"Hello from ESP32 #{message_count}"
            if await e.asend(peer, message, sync=True):
                print(f"Sent message: {message}")
            else:
                print("Failed to send message")
            message_count += 1
            await asyncio.sleep(1)  # Send every 1 second
        except OSError as err:
            print("Send error:", err)
            await asyncio.sleep(5)

Fonction pour recevoir des messages ESP-Now

Nous devons également créer une fonction pour recevoir les messages ESP-Now. Lorsqu’il y a un nouveau message, nous l’avons imprimé dans le shell Micropython.

# Async function to receive messages
async def receive_messages(e):
    while True:
        try:
            async for mac, msg in e:
                print(f"Received from {mac.hex()}: {msg.decode()}")
        except OSError as err:
            print("Receive error:", err)
            await asyncio.sleep(5)

Imprimez les statistiques ESP-Now

Ensuite, nous créons un message à appeler plus tard dans le code, appelé print_stats () qui imprime les statistiques actuelles sur les paquets ESP-Now. Pour obtenir le nombre de paquets envoyés / reçus et perdus, nous pouvons appeler la méthode statistiques () sur l’objet ESP-Now E.

Cela renvoie un 5-Tuple contenant le nombre de paquets envoyés / reçus / perdus:

(tx_pkts, tx_responses, tx_failures, rx_packets, rx_dropped_packets)

Il s’agit de la fonction asynchrone complète.

async def print_stats(e):
    global last_stats_time
    while True:
        if time.time() - last_stats_time >= stats_interval:
            stats = e.stats()
            print("\nESP-NOW Statistics:")
            print(f"  Packets Sent: {stats[0]}")
            print(f"  Packets Delivered: {stats[1]}")
            print(f"  Packets Dropped (TX): {stats[2]}")
            print(f"  Packets Received: {stats[3]}")
            print(f"  Packets Dropped (RX): {stats[4]}")
            last_stats_time = time.time()
        await asyncio.sleep(1)  # Check every second

Fonction asynchrone principale

La ligne suivante définit une fonction asynchrone Main () qui prend l’objet ESP-Now E et l’adresse MAC par les pairs comme arguments.

async def main(e, peer):

Ensuite, nous utilisons Asyncio.gather pour exécuter trois tâches asynchrones simultanément:

  • Send_Messages (E, Peer): Envoie des données de capteur BME280 au pair;
  • reçoile_messages (e): écoute les données entrantes du pair;
  • print_stats (e): imprime périodiquement les statistiques ESP-Now.
await asyncio.gather(send_messages(e, peer), receive_messages(e), print_stats(e))

Exécution du programme asynchrone

Enfin, les lignes suivantes exécuteront le programme de manière asynchrone.

# Run the async program
try:
    asyncio.run(main(e, peer_mac))
except KeyboardInterrupt:
    print("Stopping transceiver...")
    e.active(False)
    sta.active(False)

Cette commande asyncio.run (main (e, peer_mac)) démarre la boucle d’événement MicropyThon Asyncio, exécutant la fonction Main ().

Cela va à l’intérieur d’essayer et d’exaucer les instructions pour attraper un clavier Interrup (arrêtant manuellement le code). Lorsque cela se produit, nous désactivons ESP-now et désactivons le Wi-Fi.

Exécution du code

Après avoir connecté la carte à votre ordinateur et établi une communication avec Thonny IDE, vous pouvez télécharger le code en tant que main.py sur la carte ou l’exécuter à l’aide du bouton d’exécution verte. Assurez-vous d’avoir inséré l’adresse MAC du récepteur dans le code.

Exécution du code Thonny Ide Micropython

Il commencera à imprimer des messages dans le shell. Il ne parviendra pas à envoyer le message tandis que l’autre carte n’est toujours pas prête.

Ouvrez une autre instance de Thonny IDE et établissez une communication avec l’autre conseil d’administration.

Activer deux instances de thonny ide

Accédez à des outils> Options et décochez l’option autorisez uniquement l’instance Thonny.

Copiez le même code, mais insérez l’autre adresse MAC de la carte. Après quelques secondes, il commencera à envoyer et à recevoir des messages ESP-Now.

Deux planches ESP32 avec une étiquette avec leurs adresses MAC

Les captures d’écran suivantes montrent la coque micropython pour chacune de mes planches.

ESP32 ESP-Now Transmetteur Communication bidirectionnelle - Impression des résultats sur la coque Micropython
ESP32 ESP-Now Transmetteur Communication bidirectionnelle - Impression des résultats sur la coque Micropython

Vous pouvez voir qu’après avoir alimenté les deux planches, ils commenceront à échanger des messages entre eux.


ESP32 ESP-NOW Communication bidirectionnelle – Échange de lectures de capteurs et affichage sur OLED

Dans cette section, nous allons construire un projet avec une application du monde réel dans lequel les deux cartes ESP32 échangent des lectures de capteurs et afficher les données reçues sur un écran OLED.

ESP32 ESP-NOW Communication bidirectionnelle - lectures de capteurs d'échange et affichage sur OLED

Aperçu du projet

Le diagramme suivant montre un aperçu de haut niveau du projet que nous construirons.

Communication bidirectionnelle ESP-NOW - Envoyez des lectures de capteurs entre les conseils d'administration
  • Dans ce projet, nous aurons deux planches ESP32. Chaque carte est connectée à un écran OLED et à un capteur BME280;
  • Chaque planche obtient des lectures de température, d’humidité et de pression de ses capteurs correspondants;
  • Chaque planche envoie ses lectures à l’autre tableau via ESP-Now;
  • Lorsqu’une carte reçoit les lectures, elle les affiche sur l’écran OLED;
  • Après avoir envoyé les lectures, la carte s’affiche sur l’OLED si le message a été livré avec succès;
  • Chaque carte doit connaître l’autre adresse MAC pour envoyer le message.

Dans cet exemple, nous utilisons une communication bidirectionnelle entre deux planches, mais vous pouvez ajouter plus de planches à cette configuration, et avoir toutes les cartes communiquant entre elles.

Pièces requises

Pour ce tutoriel, vous avez besoin des parties suivantes:

Vous pouvez utiliser les liens précédents ou aller directement à makeradvisor.com/tools pour trouver toutes les pièces de vos projets au meilleur prix!

1755793865 801 Micropython ESP32 ESP Now Communication bidirectionnelle

Diagramme schématique

Tirez un écran OLED et un capteur BME280 à chaque carte ESP32. Suivez le diagramme schématique suivant (ajustez si vous utilisez un modèle ESP32 avec une épingle différente).

Diagramme schématique de câblage ESP32 au capteur BME280 et à l'affichage OLED

Vous pouvez utiliser le tableau suivant comme référence lors du câblage du capteur BME280.

BME280 ESP32
Vin 3.3 V
GND GND
SCL GPIO 22
SDA GPIO 21

Vous pouvez également suivre la table suivante pour câbler l’écran OLED à l’ESP32.

Affichage OLED ESP32
GND GND
VDD / VCC Vin
SCK / SCL GPIO 22
SDA GPIO 21

Importation de bibliothèques

Les bibliothèques pour s’interfacer avec l’affichage OLED et les données BME280 ne font pas partie du package Micropython standard. Nous devons donc importer ces modules dans nos conseils.

Module SSD1306.PY Micropython

1. Copiez le code suivant dans un nouveau fichier sur Thonny IDE.

# MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit

import time
import framebuf

# register definitions
SET_CONTRAST        = const(0x81)
SET_ENTIRE_ON       = const(0xa4)
SET_NORM_INV        = const(0xa6)
SET_DISP            = const(0xae)
SET_MEM_ADDR        = const(0x20)
SET_COL_ADDR        = const(0x21)
SET_PAGE_ADDR       = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP       = const(0xa0)
SET_MUX_RATIO       = const(0xa8)
SET_COM_OUT_DIR     = const(0xc0)
SET_DISP_OFFSET     = const(0xd3)
SET_COM_PIN_CFG     = const(0xda)
SET_DISP_CLK_DIV    = const(0xd5)
SET_PRECHARGE       = const(0xd9)
SET_VCOM_DESEL      = const(0xdb)
SET_CHARGE_PUMP     = const(0x8d)


class SSD1306:
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        # Note the subclass must initialize self.framebuf to a framebuffer.
        # This is necessary because the underlying data buffer is different
        # between I2C and SPI implementations (I2C needs an extra byte).
        self.poweron()
        self.init_display()

    def init_display(self):
        for cmd in (
            SET_DISP | 0x00, # off
            # address setting
            SET_MEM_ADDR, 0x00, # horizontal
            # resolution and layout
            SET_DISP_START_LINE | 0x00,
            SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
            SET_MUX_RATIO, self.height - 1,
            SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
            SET_DISP_OFFSET, 0x00,
            SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
            # timing and driving scheme
            SET_DISP_CLK_DIV, 0x80,
            SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
            SET_VCOM_DESEL, 0x30, # 0.83*Vcc
            # display
            SET_CONTRAST, 0xff, # maximum
            SET_ENTIRE_ON, # output follows RAM contents
            SET_NORM_INV, # not inverted
            # charge pump
            SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
            SET_DISP | 0x01): # on
            self.write_cmd(cmd)
        self.fill(0)
        self.show()

    def poweroff(self):
        self.write_cmd(SET_DISP | 0x00)

    def contrast(self, contrast):
        self.write_cmd(SET_CONTRAST)
        self.write_cmd(contrast)

    def invert(self, invert):
        self.write_cmd(SET_NORM_INV | (invert & 1))

    def show(self):
        x0 = 0
        x1 = self.width - 1
        if self.width == 64:
            # displays with width of 64 pixels are shifted by 32
            x0 += 32
            x1 += 32
        self.write_cmd(SET_COL_ADDR)
        self.write_cmd(x0)
        self.write_cmd(x1)
        self.write_cmd(SET_PAGE_ADDR)
        self.write_cmd(0)
        self.write_cmd(self.pages - 1)
        self.write_framebuf()

    def fill(self, col):
        self.framebuf.fill(col)

    def pixel(self, x, y, col):
        self.framebuf.pixel(x, y, col)

    def scroll(self, dx, dy):
        self.framebuf.scroll(dx, dy)

    def text(self, string, x, y, col=1):
        self.framebuf.text(string, x, y, col)


class SSD1306_I2C(SSD1306):
    def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
        self.i2c = i2c
        self.addr = addr
        self.temp = bytearray(2)
        # Add an extra byte to the data buffer to hold an I2C data/command byte
        # to use hardware-compatible I2C transactions.  A memoryview of the
        # buffer is used to mask this byte from the framebuffer operations
        # (without a major memory hit as memoryview doesn't copy to a separate
        # buffer).
        self.buffer = bytearray(((height // 8) * width) + 1)
        self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
        self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.temp[0] = 0x80 # Co=1, D/C#=0
        self.temp[1] = cmd
        self.i2c.writeto(self.addr, self.temp)

    def write_framebuf(self):
        # Blast out the frame buffer using a single I2C transaction to support
        # hardware I2C interfaces.
        self.i2c.writeto(self.addr, self.buffer)

    def poweron(self):
        pass


class SSD1306_SPI(SSD1306):
    def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
        self.rate = 10 * 1024 * 1024
        dc.init(dc.OUT, value=0)
        res.init(res.OUT, value=0)
        cs.init(cs.OUT, value=1)
        self.spi = spi
        self.dc = dc
        self.res = res
        self.cs = cs
        self.buffer = bytearray((height // 8) * width)
        self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.low()
        self.cs.low()
        self.spi.write(bytearray([cmd]))
        self.cs.high()

    def write_framebuf(self):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.high()
        self.cs.low()
        self.spi.write(self.buffer)
        self.cs.high()

    def poweron(self):
        self.res.high()
        time.sleep_ms(1)
        self.res.low()
        time.sleep_ms(10)
        self.res.high()

Afficher le code brut

2. Allez dans le fichier> Enregistrer AS et sélectionner le périphérique Micropython.

Thonny IDE Enregistrer sur le dispositif Micropython

3. Nommez le fichier ssd1306.py et cliquez sur OK pour enregistrer le fichier sur le système de fichiers ESP.

Et c’est tout. La bibliothèque a été téléchargée sur votre carte.

Module BME280.py Micropython

1. Copiez le code suivant dans un nouveau fichier sur Thonny IDE.

from machine import I2C
import time

# BME280 default address.
BME280_I2CADDR = 0x76

# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5

# BME280 Registers

BME280_REGISTER_DIG_T1 = 0x88  # Trimming parameter registers
BME280_REGISTER_DIG_T2 = 0x8A
BME280_REGISTER_DIG_T3 = 0x8C

BME280_REGISTER_DIG_P1 = 0x8E
BME280_REGISTER_DIG_P2 = 0x90
BME280_REGISTER_DIG_P3 = 0x92
BME280_REGISTER_DIG_P4 = 0x94
BME280_REGISTER_DIG_P5 = 0x96
BME280_REGISTER_DIG_P6 = 0x98
BME280_REGISTER_DIG_P7 = 0x9A
BME280_REGISTER_DIG_P8 = 0x9C
BME280_REGISTER_DIG_P9 = 0x9E

BME280_REGISTER_DIG_H1 = 0xA1
BME280_REGISTER_DIG_H2 = 0xE1
BME280_REGISTER_DIG_H3 = 0xE3
BME280_REGISTER_DIG_H4 = 0xE4
BME280_REGISTER_DIG_H5 = 0xE5
BME280_REGISTER_DIG_H6 = 0xE6
BME280_REGISTER_DIG_H7 = 0xE7

BME280_REGISTER_CHIPID = 0xD0
BME280_REGISTER_VERSION = 0xD1
BME280_REGISTER_SOFTRESET = 0xE0

BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4
BME280_REGISTER_CONFIG = 0xF5
BME280_REGISTER_PRESSURE_DATA = 0xF7
BME280_REGISTER_TEMP_DATA = 0xFA
BME280_REGISTER_HUMIDITY_DATA = 0xFD


class Device:
  """Class for communicating with an I2C device.

  Allows reading and writing 8-bit, 16-bit, and byte array values to
  registers on the device."""

  def __init__(self, address, i2c):
    """Create an instance of the I2C device at the specified address using
    the specified I2C interface object."""
    self._address = address
    self._i2c = i2c

  def writeRaw8(self, value):
    """Write an 8-bit value on the bus (without register)."""
    value = value & 0xFF
    self._i2c.writeto(self._address, value)

  def write8(self, register, value):
    """Write an 8-bit value to the specified register."""
    b=bytearray(1)
    b[0]=value & 0xFF
    self._i2c.writeto_mem(self._address, register, b)

  def write16(self, register, value):
    """Write a 16-bit value to the specified register."""
    value = value & 0xFFFF
    b=bytearray(2)
    b[0]= value & 0xFF
    b[1]= (value>>8) & 0xFF
    self.i2c.writeto_mem(self._address, register, value)

  def readRaw8(self):
    """Read an 8-bit value on the bus (without register)."""
    return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF

  def readU8(self, register):
    """Read an unsigned byte from the specified register."""
    return int.from_bytes(
        self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF

  def readS8(self, register):
    """Read a signed byte from the specified register."""
    result = self.readU8(register)
    if result > 127:
      result -= 256
    return result

  def readU16(self, register, little_endian=True):
    """Read an unsigned 16-bit value from the specified register, with the
    specified endianness (default little endian, or least significant byte
    first)."""
    result = int.from_bytes(
        self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
    if not little_endian:
      result = ((result << 8) & 0xFF00) + (result >> 8)
    return result

  def readS16(self, register, little_endian=True):
    """Read a signed 16-bit value from the specified register, with the
    specified endianness (default little endian, or least significant byte
    first)."""
    result = self.readU16(register, little_endian)
    if result > 32767:
      result -= 65536
    return result

  def readU16LE(self, register):
    """Read an unsigned 16-bit value from the specified register, in little
    endian byte order."""
    return self.readU16(register, little_endian=True)

  def readU16BE(self, register):
    """Read an unsigned 16-bit value from the specified register, in big
    endian byte order."""
    return self.readU16(register, little_endian=False)

  def readS16LE(self, register):
    """Read a signed 16-bit value from the specified register, in little
    endian byte order."""
    return self.readS16(register, little_endian=True)

  def readS16BE(self, register):
    """Read a signed 16-bit value from the specified register, in big
    endian byte order."""
    return self.readS16(register, little_endian=False)


class BME280:
  def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
               **kwargs):
    # Check that mode is valid.
    if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
                    BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
        raise ValueError(
            'Unexpected mode value {0}. Set mode to one of '
            'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
            'BME280_ULTRAHIGHRES'.format(mode))
    self._mode = mode
    # Create I2C device.
    if i2c is None:
      raise ValueError('An I2C object is required.')
    self._device = Device(address, i2c)
    # Load calibration values.
    self._load_calibration()
    self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
    self.t_fine = 0

  def _load_calibration(self):

    self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
    self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
    self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)

    self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
    self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
    self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
    self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
    self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
    self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
    self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
    self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
    self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)

    self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
    self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
    self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
    self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)

    h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
    h4 = (h4 << 24) >> 20
    self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)

    h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
    h5 = (h5 << 24) >> 20
    self.dig_H5 = h5 | (
        self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)

  def read_raw_temp(self):
    """Reads the raw (uncompensated) temperature from the sensor."""
    meas = self._mode
    self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
    meas = self._mode << 5 | self._mode << 2 | 1
    self._device.write8(BME280_REGISTER_CONTROL, meas)
    sleep_time = 1250 + 2300 * (1 << self._mode)

    sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
    sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
    time.sleep_us(sleep_time)  # Wait the required time
    msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
    lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
    xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
    raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
    return raw

  def read_raw_pressure(self):
    """Reads the raw (uncompensated) pressure level from the sensor."""
    """Assumes that the temperature has already been read """
    """i.e. that enough delay has been provided"""
    msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
    lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
    xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
    raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
    return raw

  def read_raw_humidity(self):
    """Assumes that the temperature has already been read """
    """i.e. that enough delay has been provided"""
    msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
    lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
    raw = (msb << 8) | lsb
    return raw

  def read_temperature(self):
    """Get the compensated temperature in 0.01 of a degree celsius."""
    adc = self.read_raw_temp()
    var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
    var2 = ((
        (((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
        self.dig_T3) >> 14
    self.t_fine = var1 + var2
    return (self.t_fine * 5 + 128) >> 8

  def read_pressure(self):
    """Gets the compensated pressure in Pascals."""
    adc = self.read_raw_pressure()
    var1 = self.t_fine - 128000
    var2 = var1 * var1 * self.dig_P6
    var2 = var2 + ((var1 * self.dig_P5) << 17)
    var2 = var2 + (self.dig_P4 << 35)
    var1 = (((var1 * var1 * self.dig_P3) >> 8) +
            ((var1 * self.dig_P2) >> 12))
    var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
    if var1 == 0:
      return 0
    p = 1048576 - adc
    p = (((p << 31) - var2) * 3125) // var1
    var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
    var2 = (self.dig_P8 * p) >> 19
    return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)

  def read_humidity(self):
    adc = self.read_raw_humidity()
    # print 'Raw humidity = {0:d}'.format (adc)
    h = self.t_fine - 76800
    h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
         16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
                          self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
                          self.dig_H2 + 8192) >> 14))
    h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
    h = 0 if h < 0 else h
    h = 419430400 if h > 419430400 else h
    return h >> 12

  @property
  def temperature(self):
    "Return the temperature in degrees."
    t = self.read_temperature()
    ti = t // 100
    td = t - ti * 100
    return "{}.{:02d}C".format(ti, td)

  @property
  def pressure(self):
    "Return the temperature in hPa."
    p = self.read_pressure() // 256
    pi = p // 100
    pd = p - pi * 100
    return "{}.{:02d}hPa".format(pi, pd)

  @property
  def humidity(self):
    "Return the humidity in percent."
    h = self.read_humidity()
    hi = h // 1024
    hd = h * 100 // 1024 - hi * 100
    return "{}.{:02d}%".format(hi, hd)

Afficher le code brut

2. Allez dans le fichier> Enregistrer sous…

Thonny IDE ESP32 ESP8266 Micropython Enregistrer la bibliothèque de fichiers à l'appareil Enregistrer sous

3. Sélectionnez Enregistrer sur «Micropython Device»:

Thonny IDE ESP32 ESP8266 Micropython Enregistrer la bibliothèque de fichiers à Sélection de l'appareil

4. Nommez votre fichier comme bme280.py et appuyez sur le bouton OK:

Bibliothèque BME280 Nouveau fichier micropython thonny ide

Et c’est tout. La bibliothèque a été téléchargée sur votre carte.

ESP32 Échange de lectures de capteurs BME280 via ESP-NOW – Code micropython

Maintenant que vous avez tous les modules requis téléchargés sur vos planches, vous pouvez télécharger le code suivant sur chacun de vos planches.

Important: n’oubliez pas d’insérer l’adresse MAC du récepteur sur le code.

# Rui Santos & Sara Santos - Raspberryme.com
# Complete project details at https://Raspberryme.com/micropython-esp32-esp-now-two-way/

import network
import aioespnow
import asyncio
import time
import ujson
from machine import Pin, I2C
import BME280
import ssd1306

# Initialize I2C for BME280 and SSD1306
i2c = I2C(0, scl=Pin(22), sda=Pin(21))

# Initialize BME280 sensor
try:
    bme = BME280.BME280(i2c=i2c, address=0x76)
    print("BME280 initialized")
except Exception as err:
    print("Failed to initialize BME280:", err)
    raise

# Initialize SSD1306 OLED display
try:
    display = ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
    print("SSD1306 initialized")
except Exception as err:
    print("Failed to initialize SSD1306:", err)
    raise

# Initialize Wi-Fi in station mode
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.config(channel=1) # set Wi-Fi channel for more stable communication
sta.disconnect()
print("Wi-Fi initialized")

# Initialize AIOESPNow
e = aioespnow.AIOESPNow()
try:
    e.active(True)
    print("AIOESPNow initialized")
except OSError as err:
    print("Failed to initialize AIOESPNow:", err)
    raise

# Receiver MAC address (the board you want to send data to)
peer_mac = b'\xff\xff\xff\xff\xff\xff'

# Add peer
try:
    e.add_peer(peer_mac)
except OSError as err:
    print("Failed to add peer:", err)
    raise

# Variables to store readings and status
last_send_status = " "
incoming_readings = {'temp': 0.0, 'hum': 0.0, 'pres': 0.0}

# Function to get BME280 readings
def get_readings():
    try:
        temp = float(bme.temperature[:-1]) # Remove 'C'
        hum = float(bme.humidity[:-1])     # Remove '%'
        pres = float(bme.pressure[:-3])    # Remove 'hPa'
        print("BME280 readings:", temp, hum, pres)
        return temp, hum, pres
    except Exception as err:
        print("Error reading BME280:", err)
        return 0.0, 0.0, 0.0

# Function to update OLED display
def update_display():
    try:
        display.fill(0)
        display.text("INCOM. READINGS", 0, 0)
        display.text("Temp: {:.1f} C".format(incoming_readings['temp']), 0, 15)
        display.text("Hum: {:.1f} %".format(incoming_readings['hum']), 0, 25)
        display.text("Pres: {:.1f} hPa".format(incoming_readings['pres']), 0, 35)
        display.text(last_send_status, 0, 55)
        display.show()
        print("Display updated")
    except Exception as err:
        print("Error updating display:", err)

# Async function to send messages
async def send_messages(e, peer):
    global last_send_status
    while True:
        try:
            print("Sending data")
            temp, hum, pres = get_readings()
            # Create JSON string
            data_dict = {"temp": temp, "hum": hum, "pres": pres}
            json_str = ujson.dumps(data_dict)
            data = json_str.encode('utf-8')  # Convert to bytes
            print("Sending JSON:", json_str)
            if await e.asend(peer, data, sync=True):
                print("Sent with success")
                last_send_status = "Delivery Success :)"
            else:
                print("Send failed")
                last_send_status = "Delivery Fail :("
            update_display()
            print("Sending task complete")
            await asyncio.sleep(10)  # Send every 10 seconds
        except OSError as err:
            print("Send error:", err)
            last_send_status = "Delivery Fail :("
            update_display()
            await asyncio.sleep(0.1)  # Shorter delay in case of error

# Async function to receive messages
async def receive_messages(e):
    global incoming_readings
    while True:
        try:
            print("Checking for messages")
            async for mac, msg in e:
                try:
                    # Decode bytes to string and parse JSON
                    json_str = msg.decode('utf-8')
                    data_dict = ujson.loads(json_str)
                    temp = data_dict['temp']
                    hum = data_dict['hum']
                    pres = data_dict['pres']
                    incoming_readings['temp'] = temp
                    incoming_readings['hum'] = hum
                    incoming_readings['pres'] = pres
                    print("\nINCOMING READINGS")
                    print("Temperature: {:.1f} ºC".format(temp))
                    print("Humidity: {:.1f} %".format(hum))
                    print("Pressure: {:.1f} hPa".format(pres))
                    update_display()
                except (ValueError, KeyError) as err:
                    print("Error parsing JSON:", err)
            await asyncio.sleep(0.01)  # Yield if no received messages
        except OSError as err:
            print("Receive error:", err)
            await asyncio.sleep(0.1)  # Shorter delay in case of error

# Main async function
async def main(e, peer):
    print("Starting main loop")
    await asyncio.gather(send_messages(e, peer), receive_messages(e))

# Run the async program
try:
    print("Starting transceiver...")
    asyncio.run(main(e, peer_mac))
except KeyboardInterrupt:
    print("Stopping transceiver...")
    e.active(False)
    sta.active(False)
except Exception as err:
    print("Main loop error:", err)
finally:
    print("Cleaning up...")
    e.active(False)
    sta.active(False)

Afficher le code brut

Comment fonctionne le code?

Voyons rapidement comment fonctionne le code. Alternativement, vous pouvez passer à la section de démonstration.

Importation de bibliothèques

Nous commençons par importer les modules requis.

import network
import aioespnow
import asyncio
import time
import ujson
from machine import Pin, I2C
import BME280
import ssd1306

Communication I2C

Initialisez une communication I2C sur GPIOS 22 et 21. Ajustez si vous utilisez différentes broches.

i2c = I2C(0, scl=Pin(22), sda=Pin(21))

BME280

Initialisez le capteur BME280.

# Initialize BME280 sensor
try:
    bme = BME280.BME280(i2c=i2c, address=0x76)
    print("BME280 initialized")
except Exception as err:
    print("Failed to initialize BME280:", err)
    raise

Affichage OLED

Initialiser l’affichage OLED.

# Initialize SSD1306 OLED display
try:
    display = ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
    print("SSD1306 initialized")
except Exception as err:
    print("Failed to initialize SSD1306:", err)
    raise

Initialiser l’interface Wi-Fi

Ensuite, nous devons initialiser le Wi-Fi (même si nous ne l’utilisons pas) pour utiliser ESP-Now. Nous pouvons utiliser la station (STA_IF) ou le mode Point d’accès (AP_IF).

# Initialize Wi-Fi in station mode
sta = network.WLAN(network.STA_IF)
sta.active(True)
sta.config(channel=1)  # Set channel 
sta.disconnect()

Initialiser ESP-now

Ensuite, nous pouvons initialiser ESP-Now. Tout d’abord, créez une instance aioespnow appelée e. Puis activez-le en utilisant la méthode active () et en passant la valeur vraie en tant qu’argument.

# Initialize AIOESPNow
e = aioespnow.AIOESPNow()
try:
    e.active(True)
    print("AIOESPNow initialized")
except OSError as err:
    print("Failed to initialize AIOESPNow:", err)
    raise

Nous activons ESP-NOW à l’intérieur d’un essai et sauf des instructions afin que nous puissions prendre des erreurs en cas d’échec de l’initialisation.

Ajouter un pair ESP-now

Insérez l’adresse MAC par les pairs (l’adresse MAC de la carte à laquelle vous souhaitez envoyer des données).

# Receiver MAC address (the board you want to send data to)
peer_mac = b'\x68\xb6\xb3\x22\x9e\x60'

Ensuite, nous pouvons ajouter l’adresse MAC du récepteur en tant que pair à l’aide de la méthode add_peer ().

try:
    e.add_peer(peer_mac)
except OSError as err:
    print("Failed to add peer:", err)
    raise

Variables

Créez des variables pour stocker les lectures des capteurs entrants et l’état du processus d’envoi. Nous économisons les lectures de capteurs entrants dans un dictionnaire.

last_send_status = " "
incoming_readings = {'temp': 0.0, 'hum': 0.0, 'pres': 0.0}

Obtenez des lectures de capteurs BME280

La fonction get_readings () renvoie les lectures du capteur BME280 dans cet ordre, la température, l’humidité et la pression. Les fonctions de la bibliothèque BME280 renvoient les résultats avec le caractère de l’unité, c’est pourquoi nous supprimons les caractères à la fin des lectures.

Dans le cas où il y a une erreur en lisant le capteur, il renverra 0,0 pour toutes les lectures.

# Function to get BME280 readings
def get_readings():
    try:
        temp = float(bme.temperature[:-1]) # Remove 'C'
        hum = float(bme.humidity[:-1])     # Remove '%'
        pres = float(bme.pressure[:-3])    # Remove 'hPa'
        print("BME280 readings:", temp, hum, pres)
        return temp, hum, pres
    except Exception as err:
        print("Error reading BME280:", err)
        return 0.0, 0.0, 0.0

Mettre à jour l’écran OLED

La fonction suivante met à jour l’affichage avec les lectures actuelles des capteurs entrants. Il affiche également le dernier statut d’envoi.

# Function to update OLED display
def update_display():
    try:
        display.fill(0)
        display.text("INCOM. READINGS", 0, 0)
        display.text("Temp: {:.1f} C".format(incoming_readings['temp']), 0, 15)
        display.text("Hum: {:.1f} %".format(incoming_readings['hum']), 0, 25)
        display.text("Pres: {:.1f} hPa".format(incoming_readings['pres']), 0, 35)
        display.text(last_send_status, 0, 55)
        display.show()
        print("Display updated")
    except Exception as err:
        print("Error updating display:", err)

Pour en savoir plus sur l’utilisation de l’affichage OLED avec l’ESP32 programmé avec Micropython, vérifiez notre guide: Micropython: Affichage OLED avec ESP32 et ESP8266.

La fonction Send_Message (E, Peer) envoie un message au pair spécifié à l’aide d’une instance ESPNow e.

# Async function to send messages
async def send_messages(e, peer):
    global last_send_status
    while True:
        try:
            print("Sending data")
            temp, hum, pres = get_readings()
            # Create JSON string
            data_dict = {"temp": temp, "hum": hum, "pres": pres}
            json_str = ujson.dumps(data_dict)
            data = json_str.encode('utf-8')  # Convert to bytes
            print("Sending JSON:", json_str)
            if await e.asend(peer, data, sync=True):
                print("Sent with success")
                last_send_status = "Delivery Success :)"
            else:
                print("Send failed")
                last_send_status = "Delivery Fail :("
            update_display()
            print("Sending task complete")
            await asyncio.sleep(10)  # Send every 10 seconds
        except OSError as err:
            print("Send error:", err)
            last_send_status = "Delivery Fail :("
            update_display()
            await asyncio.sleep(0.1)  # Shorter delay in case of error

Dans cette fonction, nous commençons par appeler get_readings () pour obtenir les lectures de température, d’humidité et de pression actuelles. Ensuite, nous mettons à jour le dictionnaire avec les lectures actuelles. Nous le convertissons en une chaîne JSON puis en octets.

temp, hum, pres = get_readings()
# Create JSON string
data_dict = {"temp": temp, "hum": hum, "pres": pres}
json_str = ujson.dumps(data_dict)
data = json_str.encode('utf-8')  # Convert to bytes

Ensuite, nous utilisons la même procédure que nous avons décrite précédemment pour envoyer des données. Au cours de ce processus, nous mettons également à jour l’affichage avec le résultat de l’envoi des données.

if await e.asend(peer, data, sync=True):
    print("Sent with success")
    last_send_status = "Delivery Success :)"
else:
    print("Send failed")
    last_send_status = "Delivery Fail :("
    update_display()
    print("Sending task complete")
    await asyncio.sleep(10)  # Send every 10 seconds
except OSError as err:
    print("Send error:", err)
    last_send_status = "Delivery Fail :("
    update_display()
    await asyncio.sleep(0.1)  # Shorter delay in case of error

Recevoir des données entrantes

La fonction reçoit_messages () recevra les données de l’autre carte.

# Async function to receive messages
async def receive_messages(e):
    global incoming_readings
    while True:
        try:
            print("Checking for messages")
            async for mac, msg in e:
                try:
                    # Decode bytes to string and parse JSON
                    json_str = msg.decode('utf-8')
                    data_dict = ujson.loads(json_str)
                    temp = data_dict['temp']
                    hum = data_dict['hum']
                    pres = data_dict['pres']
                    incoming_readings['temp'] = temp
                    incoming_readings['hum'] = hum
                    incoming_readings['pres'] = pres
                    print("\nINCOMING READINGS")
                    print("Temperature: {:.1f} ºC".format(temp))
                    print("Humidity: {:.1f} %".format(hum))
                    print("Pressure: {:.1f} hPa".format(pres))
                    update_display()
                except (ValueError, KeyError) as err:
                    print("Error parsing JSON:", err)
            await asyncio.sleep(0.01)  # Yield if no received messages
        except OSError as err:
            print("Receive error:", err)
            await asyncio.sleep(0.1)  # Shorter delay in case of error

Lorsque nous recevons les données, nous la convertissons en une chaîne JSON. Ensuite, nous mettons à jour le dictionnaire entrant_readings avec les données reçues.

Enfin, nous imprimons les lectures dans le moniteur série et appelons également la fonction Update_Display () pour mettre à jour l’écran avec les dernières lectures de capteurs.

Création de la fonction de boucle asynchrone et exécution du programme

Enfin, nous créons la fonction de boucle asynchrone principale et exécutons le programme de manière asynchrone comme nous l’avons fait dans l’exemple précédent.

# Run the async program
try:
    print("Starting transceiver...")
    asyncio.run(main(e, peer_mac))
except KeyboardInterrupt:
    print("Stopping transceiver...")
    e.active(False)
    sta.active(False)
except Exception as err:
    print("Main loop error:", err)
finally:
    print("Cleaning up...")
    e.active(False)
    sta.active(False)

Téléchargement du code sur vos planches

Remarque importante: le simple fait d’exécuter le fichier avec Thonny ne le copie pas en permanence au système de fichiers de la carte. Cela signifie que si vous le débranchez à partir de votre ordinateur et appliquez de l’alimentation à la carte, rien ne se passera car il n’a pas de fichier Python enregistré sur son système de fichiers. La fonction Thonny IDE Run est utile pour tester le code, mais si vous souhaitez le télécharger en permanence sur votre carte, vous devez créer et enregistrer un fichier sur le système de fichiers de la carte.

Pour exécuter le code sur vos planches sans être connecté à votre ordinateur, vous devez le télécharger sur le système de fichiers de la carte avec le nom main.py.

Allez dans Fichier> Enregistrer sous … Appareil micropython.

Thonny IDE ESP32 ESP8266 Micropython Enregistrer la bibliothèque de fichiers à Sélection de l'appareil

Appelez ce fichier main.py et enregistrez-le sur la carte.

Enregistrer le fichier main.py sur le périphérique Micropython - Thonny IDE

Démonstration

Après avoir téléchargé le code sur les deux cartes, vous devriez voir l’OLED afficher les lectures du capteur de l’autre carte, ainsi qu’un message «Succès de livraison».

ESP32 Échange de lectures de capteurs BME280 via ESP-NOW

Emballage

Nous espérons que vous avez trouvé ce guide utile. Le protocole de communication sans fil ESP-Now est l’une des méthodes les plus faciles à communiquer entre les cartes ESP32 à distance sans avoir besoin d’un routeur Wi-Fi.

Dans ce tutoriel, vous avez appris à établir une communication bidirectionnelle entre les conseils. Vous pouvez facilement ajouter plus de cartes à votre configuration en ajoutant plus de pairs pour créer un réseau de planches ESP32 qui communiquent entre elles.

Si vous ne faites que commencer avec ESP-Now, nous vous recommandons de commencer avec notre guide ESP-Now Getting pour le programme ESP32 avec Micropython.

Vous voulez en savoir plus sur Micropython avec l’ESP32? Consultez nos ressources:

Merci d’avoir lu.

Plongez dans l’histoire de Raspberry Pi avec cette vidéo :

Youtube video

  • ELEGOO 3PCS Carte de Développement ESP-32 Type-C, 2,4 GHz WiFi + Bluetooth
  • ELEGOO 2 Pièces ESP-32 Carte de Développement avec Port USB Micro