2018年12月7日 星期五

MicroPython – Getting Started with MQTT on ESP32/ESP8266

MicroPython – Getting Started with MQTT on ESP32/ESP8266

    0 Shares
    In this tutorial, we’ll show you how to use MQTT to exchange data between two ESP32/ESP8266 boards using MicroPython firmware. As an example, we’ll exchange simple text messages between two ESP boards. The idea is to use the concepts learned here to exchange sensor readings, or commands.
    MicroPython Getting Started with MQTT on ESP32/ESP8266
    Notethis tutorial is compatible with both the ESP32 and ESP8266 development boards. 

    Prerequisites

    Before continuing with this tutorial, make sure you complete the following prerequisites:

    MicroPython firmware

    To program the ESP32 and ESP8266 with MicroPython, we use uPyCraft IDE as a programming environment. Follow the next tutorials to install uPyCraft IDE and flash MicroPython firmware on your board:

    MQTT Broker

    To use MQTT, you need a broker. We’ll be using Mosquitto broker installed on a Raspberry Pi. Read How to Install Mosquitto Broker on Raspberry Pi.
    If you’re not familiar with MQTT make sure you read our introductory tutorial: What is MQTT and How It Works

    Parts Required

    For this tutorial you need two ESP32 or two ESP8266 boards:
    You also need a Raspberry Pi and the following accessories:
    You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

    Project Overview

    Here’s a high-level overview of the project we’ll build:
    • ESP#1 publishes messages on the hello topic. It publishes a “Hello” message followed by a counter (Hello 1, Hello 2, Hello 3, …). It publishes a new message every 5 seconds.
    • ESP#1 is subscribed to the notification topic to receive notifications from the ESP#2 board.
    • ESP#2 is subscribed to the hello topic. ESP #1 is publishing in this topic. Therefore, ESP#2 receives ESP#1 messages.
    • When ESP#2 receives the messages, it sends a message saying ‘received’. This message is published on the notification topic. ESP#1 is subscribed to that topic, so it receives the message.

    Preparing ESP#1

    Let’s start by preparing ESP#1:
    • It is subscribed to the notification topic
    • It publishes on the hello topic

    Importing umqtttsimple library

    DOWNLOAD FREE GUIDE: ESP32 Web Server with Arduino IDE
    To use MQTT with the ESP32/ESP8266 and MicroPython, you need to install the umqttsimple library.
    1. Create a new file by pressing the New File button.
    2. Copy the umqttsimple library code into it. You can access the umqttsimple library code in the following link:
    3. Save the file by pressing the Save button.
    4. Call this new file “umqttsimple.py” and press ok.
    5. Click the Download and Run button.
    6. The file should be saved on the device folder with the name “umqttsimple.py” as highlighted in the figure below.
    Now, you can use the library functionalities in your code by importing the library.

    boot.py

    Open the boot.py file and copy the following code to ESP#1.
    # Complete project details at https://RandomNerdTutorials.com
    import timefrom umqttsimple import MQTTClient
    import ubinasciiimport machineimport micropythonimport networkimport esp
    esp.osdebug(None)
    import gc
    gc.collect()
    
    ssid = 'REPLACE_WITH_YOUR_SSID'
    password = 'REPLACE_WITH_YOUR_PASSWORD'
    mqtt_server = 'REPLACE_WITH_YOUR_MQTT_BROKER_IP'
    #EXAMPLE IP ADDRESS
    #mqtt_server = '192.168.1.144'
    client_id = ubinascii.hexlify(machine.unique_id())
    topic_sub = b'notification'
    topic_pub = b'hello'
    
    last_message = 0
    message_interval = 5
    counter = 0
    
    station = network.WLAN(network.STA_IF)
    
    station.active(True)
    station.connect(ssid, password)
    while station.isconnected() == False:
      pass
    print('Connection successful')
    print(station.ifconfig())

    How the Code Works

    You need to import all the following libraries:
    import time
    from umqttsimple import MQTTClient
    import ubinascii
    import machine
    import micropython
    import network
    import esp
    Set the debug to None and activate the garbage collector.
    esp.osdebug(None)
    import gc
    gc.collect()
    In the following variables, you need to enter your network credentials and your broker IP address.
    ssid = 'REPLACE_WITH_YOUR_SSID'
    password = 'REPLACE_WITH_YOUR_PASSWORD'
    mqtt_server = 'REPLACE_WITH_YOUR_MQTT_BROKER_IP'
    For example, our broker IP address is: 192.168.1.144.
    Note: read this tutorial to see how to get your broker IP address:
    To create an MQTT client, we need to get the ESP unique ID. That’s what we do in the following line (it is saved on the client_id variable).
    client_id = ubinascii.hexlify(machine.unique_id())
    Next, write the topic the ESP#1 is subscribed to, and the topic it will be publishing messages:
    topic_sub = b'notification'
    topic_pub = b'hello'
    Then, create the following variables:
    last_message = 0
    message_interval = 5
    counter = 0
    The last_message variable will hold the last time a message was sent. The message_intervalis the time between each message sent. Here, we’re setting it to 5 seconds (this means a new message will be sent every 5 seconds). The counter variable is simply a counter to be added to the message.
    After that, we make the procedures to connect to the network.
    station = network.WLAN(network.STA_IF)
    
    station.active(True)
    station.connect(ssid, password)
    
    while station.isconnected() == False:
      pass
    
    print('Connection successful')
    print(station.ifconfig())

    main.py

    In the main.py file is where we’ll write the code to publish and receive the messages. Copy the following code to your main.py file.
    # Complete project details at https://RandomNerdTutorials.com
    def sub_cb(topic, msg):
      print((topic, msg))
      if topic == b'notification' and msg == b'received':
        print('ESP received hello message')
    def connect_and_subscribe():
      global client_id, mqtt_server, topic_sub
      client = MQTTClient(client_id, mqtt_server)
      client.set_callback(sub_cb)
      client.connect()
      client.subscribe(topic_sub)
      print('Connected to %s MQTT broker, subscribed to %s topic' % (mqtt_server, topic_sub))
      return client
    def restart_and_reconnect():
      print('Failed to connect to MQTT broker. Reconnecting...')
      time.sleep(10)
      machine.reset()
    try:
      client = connect_and_subscribe()
    except OSError as e:
      restart_and_reconnect()
    while True:
      try:
        client.check_msg()
        if (time.time() - last_message) > message_interval:
          msg = b'Hello #%d' % counter
          client.publish(topic_pub, msg)
          last_message = time.time()
          counter += 1
      except OSError as e:
        restart_and_reconnect()

    How the code works

    The first thing you should do is creating a callback function that will run whenever a message is published on a topic the ESP is subscribed to.

    Callback function

    The callback function should accept as parameters the topic and the message.
    def sub_cb(topic, msg):
      print((topic, msg))
      if topic == b'notification' and msg == b'received':
        print('ESP received hello message')
    In our callback function, we start by printing the topic and the message. Then, we check if the message was published on the notification topic, and if the content of the message is ‘received’. If this if statement is True, it means that ESP#2 received the ‘hello’ message sent by ESP#1.
    Basically, this callback function handles what happens when a certain message is received on a certain topic.

    Connect and subscribe

    Then, we have the connect_and_subscribe() function. This function is responsible for connecting to the broker as well as to subscribe to a topic.
    def connect_and_subscribe():
    Start by declaring the client_idmqtt_server and topic_sub variables as global variables. This way, we can access these variables throughout the code.
    global client_id, mqtt_server, topic_sub
    Then, create a MQTTClient object called client. We need to pass as parameters the cliend_id, and the IP address of the MQTT broker (mqtt_server). These variables were set previously on the boot.py file.
    client = MQTTClient(client_id, mqtt_server)
    After that, set the callback function to the client (sub_cb).
    client.set_callback(sub_cb)
    Next, connect the client to the broker using the connect() method on the MQTTClientobject.
    client.connect()
    After connecting, we subscribe to the topic_sub topic. Set the topic_sub on the boot.py file (notification).
    client.subscribe(topic_sub)
    Finally, print a message and return the client:
    print('Connected to %s MQTT broker, subscribed to %s topic' % (mqtt_server, topic_sub))
    return client

    Restart and reconnect

    We create a function called restart_and_reconnect(). This function will be called in case the ESP32 or ESP8266 fails to connect to the broker.
    This function prints a message to inform that the connection was not successful. We wait 10 seconds. Then, we reset the ESP using the reset() method.
    def restart_and_reconnect():
      print('Failed to connect to MQTT broker. Reconnecting...')
      time.sleep(10)
      machine.reset()

    Receive and publish messages

    Until now, we’ve created functions to handle tasks related with the MQTT communication. From now on, the code will call those functions to make things happen.
    The first thing we need to do is to connect to the MQTT broker and subscribe to a topic. So, we create a client by calling the connect_and_subscribe() function.
    try:
      client = connect_and_subscribe()
    In case we’re not able to connect to the MQTTT broker, we’ll restart the ESP by calling the restart_and_reconnect() function
    except OSError as e:
      restart_and_reconnect()
    In the while loop is where we’ll be receiving and publishing the messages. We use try and except statements to prevent the ESP from crashing in case something goes wrong.
    Inside the try block, we start by applying the check_msg() method on the client.
    try:
      client.check_msg()
    The check_msg() method checks whether a pending message from the server is available. It waits for a single incoming MQTT message and process it. The subscribed messages are delivered to the callback function we’ve defined earlier (the sub_cb() function). If there isn’t a pending message, it returns with None.
    Then, we add an if statement to checker whether 5 seconds (message_interval) have passed since the last message was sent.
    if (time.time() - last_message) > message_interval:
    If it is time to send a new message, we create a msg variable with the “Hello” text followed by a counter.
    msg = b'Hello #%d' % counter
    To publish a message on a certain topic, you just need to apply the publish() method on the client and pass as arguments, the topic and the message. The topic_pub variable was set to hello in the boot.py file.
    client.publish(topic_pub, msg)
    After sending the message, we update the last time a message was received by setting the last_message variable to the current time.
    last_message = time.time()
    Finally, we increase the counter variable in every loop.
    counter += 1
    If something unexpected happens, we call the restart_and_reconnect() function.
    except OSError as e:
      restart_and_reconnect()
    That’s it for ESP#1. Remember that you need to upload all the next files to make the project work (you should upload the files in order):
    1. umqttsimple.py;
    2. boot.py;
    3. main.py.
    After uploading all files, you should get success messages on: establishing a network connection; connecting to the broker; and subscribing to the topic.

    ESP #2

    Let’s now prepare ESP#2:
    • It is subscribed to the hello topic
    • It publishes on the notification topic
    Like the ESP#1, you also need to upload the umqttsimple.pyboot.py, and main.py files.

    Importing umqttsimple

    To use MQTT with the ESP32/ESP8266 and MicroPython, you need to install the umqttsimple library. Follow the steps described earlier to install the umqttsimple library in ESP#2.
    You can access the umqttsimple library code in the following link:

    boot.py

    Copy the following code to the ESP#2 boot.py file.
    # Complete project details at https://RandomNerdTutorials.com
    import timefrom umqttsimple import MQTTClient
    import ubinasciiimport machineimport micropythonimport networkimport esp
    esp.osdebug(None)
    import gc
    gc.collect()
    
    ssid = 'REPLACE_WITH_YOUR_SSID'
    password = 'REPLACE_WITH_YOUR_PASSWORD'
    mqtt_server = 'REPLACE_WITH_YOUR_MQTT_BROKER_IP'
    #EXAMPLE IP ADDRESS
    #mqtt_server = '192.168.1.144'
    client_id = ubinascii.hexlify(machine.unique_id())
    topic_sub = b'hello'
    topic_pub = b'notification'
    
    station = network.WLAN(network.STA_IF)
    
    station.active(True)
    station.connect(ssid, password)
    while station.isconnected() == False:
      pass
    print('Connection successful')
    print(station.ifconfig())
    This code is very similar with the previous boot.py file. You need to replace the following variables with your network credentials and the broker IP address.
    ssid = 'REPLACE_WITH_YOUR_SSID'
    password = 'REPLACE_WITH_YOUR_PASSWORD'
    mqtt_server = 'REPLACE_WITH_YOUR_MQTT_BROKER_IP'
    The only difference here is that we subscribe to the hello topic and publish on the notification topic.
    topic_sub = b'hello'
    topic_pub = b'notification'

    main.py

    Copy the following code to the ESP#2 main.py file.
    # Complete project details at https://RandomNerdTutorials.com
    def sub_cb(topic, msg):
      print((topic, msg))
    def connect_and_subscribe():
      global client_id, mqtt_server, topic_sub
      client = MQTTClient(client_id, mqtt_server)
      client.set_callback(sub_cb)
      client.connect()
      client.subscribe(topic_sub)
      print('Connected to %s MQTT broker, subscribed to %s topic' % (mqtt_server, topic_sub))
      return client
    def restart_and_reconnect():
      print('Failed to connect to MQTT broker. Reconnecting...')
      time.sleep(10)
      machine.reset()
    try:
      client = connect_and_subscribe()
    except OSError as e:
      restart_and_reconnect()
    while True:
      try:
        new_message = client.check_msg()
        if new_message != 'None':
          client.publish(topic_pub, b'received')
        time.sleep(1)
      except OSError as e:
        restart_and_reconnect()
    This code is very similar with the main.py from ESP#1. We create the sub_cb(), the connect_and_subscribe() and the restart_and_reconnect() functions. This time, the sub_cb()function just prints information about the topic and received message.
    def sub_cb(topic, msg):
      print((topic, msg))
    In the while loop, we check if we got a new message and save it in the new_messagevariable.
    new_message = client.check_msg()
    If we receive a new message, we publish a message saying ‘received’ on the topic_subtopic (in this case we set it to notification in the boot.py file).
    if new_message != 'None':
      client.publish(topic_pub, b'received')
    That’s it for ESP#2. Remember that you need to upload all the next files to make the project work (you should upload the files in order):
    1. umqttsimple.py;
    2. boot.py;
    3. main.py.
    The ESP32/ESP8266 should establish a network connection and connect to the broker successfully.

    Demonstration

    After uploading all the necessary scripts to both ESP boards and having both boards and the Raspberry Pi with the Mosquitto broker running, you are ready to test the setup.
    The ESP#2 should be receiving the “Hello” messages from ESP#1, as shown in the figure below.
    On the other side, ESP#1 board should receive the “received” message. The “received” message is published by ESP#2 on the notification topic. ESP#1 is subscribed to that topic, so it receives the message.

    Wrapping Up

    In this simple example, you’ve learned how to exchange text between two ESP32/ESP8266 boards using MQTT communication protocol. The idea is to use the concepts learned here to exchange useful data like sensor readings or commands to control outputs.
    If you like MicroPython with the ESP32/ESP8266, you may also like:

    沒有留言:

    張貼留言

    Messaging API作為替代方案

      LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...