0% found this document useful (0 votes)
6 views29 pages

Lab 9

This lab report details the process of programming ESP8266 boards using MicroPython and the uPyCraft IDE to implement MQTT communication. Two ESP boards are set up, where one publishes messages to a topic and the other subscribes to it, confirming successful communication through acknowledgment messages. The report includes code snippets for the necessary libraries and scripts used to establish the MQTT connection and handle message publishing and subscribing.

Uploaded by

hananaasif2004
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views29 pages

Lab 9

This lab report details the process of programming ESP8266 boards using MicroPython and the uPyCraft IDE to implement MQTT communication. Two ESP boards are set up, where one publishes messages to a topic and the other subscribes to it, confirming successful communication through acknowledgment messages. The report includes code snippets for the necessary libraries and scripts used to establish the MQTT connection and handle message publishing and subscribing.

Uploaded by

hananaasif2004
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Practical IoT (Internet of Things)

Lab Report
Lab 9
Instructor: Dr. Naveed Akhtar
Name Registration No.

Eshal Ali 03-3-1-014-2022

Hadiqa Nadeem 03-3-1-017-2022

Hanana Asif 03-3-1-021-2022

Muhammad Ahsan Ali 03-3-1-029-2022

March 27, 2025


MicroPython – Getting Started with MQTT on
ESP32/ESP8266
This lab is about ESP8266 programming with MicroPython and uPyCraft IDE is used.

Link followed from Python and uPyCraft installation

https://randomnerdtutorials.com/install-upycraft-ide-windows-pc-instructions/

Installing python
Python was already installed on my system

Installing uPyCraft IDE


I installed uPyCraft IDE executable provided on canvas

Double Click the executable to open the uPyCraft IDE


Downloading and Flashing the MicroPython Firmware on ESP32
Link followed: https://randomnerdtutorials.com/flash-upload-micropython-firmware-
esp32-esp8266/

I downloaded ESP8266 generic firmware file from http://micropython.org/download#esp32

Selecting Serial Port


Go to Tools > Serial and selected my board which is ESP8266
And COM port 5 in my case

Updating the Firmware


I selected ESP8266 Generic Firmware binary file

And the shown options were selected


Burning Firmware
The Firmware was burnt on the ESP8266

After firmware is burnt, we can see boot.py file under the device folder. Python terminal is
also working fine. This means our firmware was successfully burnt into the ESP8266 board.

MicroPython Firmware is successfully uploaded to the ESP8266.

MQTT Broker
Now we will be publishing and subscribing MQTT messages using python, MQTT explorer
and MQTT server setup on Raspberry Pi Virtual Machine.
In this lab, we use two ESP boards which communicate using MQTT protocol. ESP#1 acts
as a publisher and subscriber. It publishes messages on the hello topic every 5 seconds,
sending "Hello" followed by a counter (e.g., Hello 1, Hello 2, etc.). Simultaneously, ESP#1
subscribes to the notification topic to receive responses. ESP#2 subscribes to the hello
topic and receives the messages published by ESP#1. Upon receiving a message, ESP#2
immediately publishes a response message saying "received" on the notification topic.
Since ESP#1 is subscribed to this topic, it receives the acknowledgment, confirming
successful communication between the two ESP boards.

For both ESPs following 3 files are Saved:

1. umqttsimple.py
2. boot.py
3. main.py

ESP No 1

Importing umqttsimple library


In uPyCraft, I created a new file and pasted the contents of umqttsimple.py in it. Then I
uploaded the file to my ESP8266 board. This library provides the necessary functions to
connect to an MQTT broker, publish messages, and subscribe to topics

umqttsimple.py
try:
import usocket as socket
except:
import socket
import ustruct as struct
from ubinascii import hexlify

class MQTTException(Exception):
pass

class MQTTClient:

def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,


ssl=False, ssl_params={}):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False

def _send_str(self, s):


self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)

def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7f) << sh
if not b & 0x80:
return n
sh += 7

def set_callback(self, f):


self.cb = f

def set_last_will(self, topic, msg, retain=False, qos=0):


assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain

def connect(self, clean_session=True):


self.sock = socket.socket()
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
self.sock.connect(addr)
if self.ssl:
import ussl
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")

sz = 10 + 2 + len(self.client_id)
msg[6] = clean_session << 1
if self.user is not None:
sz += 2 + len(self.user) + 2 + len(self.pswd)
msg[6] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[7] |= self.keepalive >> 8
msg[8] |= self.keepalive & 0x00FF
if self.lw_topic:
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[6] |= self.lw_retain << 5

i = 1
while sz > 0x7f:
premsg[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
premsg[i] = sz

self.sock.write(premsg, i + 2)
self.sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1

def disconnect(self):
self.sock.write(b"\xe0\0")
self.sock.close()

def ping(self):
self.sock.write(b"\xc0\0")

def publish(self, topic, msg, retain=False, qos=0):


pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def subscribe(self, topic, qos=0):
assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
#print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return

# Wait for a single incoming MQTT message and process it.


# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xf0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0

# Checks whether a pending message from server is available.


# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()
Saving and Downloading the umqttsimple.py file
Boot.py
# Complete project details at https://RandomNerdTutorials.com/micropython-programming-with-
esp32-and-esp8266/

import time
from umqttsimple import MQTTClient
import ubinascii
import machine
import micropython
import network
import esp
esp.osdebug(None)
import gc
gc.collect()

ssid = 'micropython'
password = 'micropython'
mqtt_server = '192.168.43.54'
mqtt_user = 'hhaeiot'
mqtt_pass = '123123'

#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())

Code Explanation
This code connects ESP8266 board to Wi-Fi and an MQTT broker to send and receive
messages. It uses the umqttsimple library we downloaded. The ESP connects to Wi-Fi
network using the provided SSID and password.

• ssid = 'micropython'
• password = 'micropython'
Then it prepares to publish messages to the topic "hello" and subscribe to messages on the
topic "notification". The device logs in to the MQTT broker using the given username and
password. Once connected, it will be able to send and receive data wirelessly.

• mqtt_server = '192.168.43.54'
• mqtt_user = 'hhaeiot'
• mqtt_pass = '123123'

The ESP uses a unique ID as the client name. It subscribes to the topic hello and publishes
messages to the topic notification.

• topic_sub = b'notification'
• topic_pub = b'hello'

Boot.py File
Main.py
# Complete project details at https://RandomNerdTutorials.com/micropython-programming-with-
esp32-and-esp8266/

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, user=mqtt_user, password=mqtt_pass)
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()

Code Explanation
This code connects ESP8266 to an MQTT server and listen for messages on a specific topic,
and send "Hello" messages to another topic regularly. It checks for messages and reacts if
it gets a certain message, like printing "ESP received hello message" when it receives a
specific message. It keeps sending "Hello" messages at regular intervals and checks for
new messages continuously.

Main.py File
Accessing the MQTT Broker
We accessed the MQTT broker through the Raspberry Pi VM IP address.

After subscribing to the required topics, we can see the messages published by the ESP#1
ESP No 2

Importing umqttsimple library


In uPyCraft, I created a new file and pasted the contents of umqttsimple.py in it. Then I
uploaded the file to my ESP8266 board. This library provides the necessary functions to
connect to an MQTT broker, publish messages, and subscribe to topics

Umqttsimple.py
try:
import usocket as socket
except:
import socket
import ustruct as struct
from ubinascii import hexlify

class MQTTException(Exception):
pass

class MQTTClient:

def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,


ssl=False, ssl_params={}):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user

self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False

def _send_str(self, s):


self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)

def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7f) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(self, f):
self.cb = f

def set_last_will(self, topic, msg, retain=False, qos=0):


assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain

def connect(self, clean_session=True):


self.sock = socket.socket()
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
self.sock.connect(addr)
if self.ssl:
import ussl
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")

sz = 10 + 2 + len(self.client_id)
msg[6] = clean_session << 1
if self.user is not None:
sz += 2 + len(self.user) + 2 + len(self.pswd)
msg[6] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[7] |= self.keepalive >> 8
msg[8] |= self.keepalive & 0x00FF
if self.lw_topic:
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)

msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[6] |= self.lw_retain << 5

i = 1
while sz > 0x7f:
premsg[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
premsg[i] = sz

self.sock.write(premsg, i + 2)
self.sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1

def disconnect(self):
self.sock.write(b"\xe0\0")
self.sock.close()

def ping(self):
self.sock.write(b"\xc0\0")

def publish(self, topic, msg, retain=False, qos=0):


pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0

def subscribe(self, topic, qos=0):


assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
#print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return

# Wait for a single incoming MQTT message and process it.


# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xf0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0

# Checks whether a pending message from server is available.


# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()
Saving and Downloading the umqttsimple.py
Boot.py
# Complete project details at https://RandomNerdTutorials.com/micropython-programming-with-
esp32-and-esp8266/

import time
from umqttsimple import MQTTClient
import ubinascii
import machine
import micropython
import network
import esp
esp.osdebug(None)
import gc
gc.collect()

ssid = 'micropython'
password = 'micropython'
mqtt_server = '192.168.43.54'
mqtt_user = 'hhaeiot'
mqtt_pass = '123123'

#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())

Code Explanation
This code is similar to the boot.py code of ESP#1. This code connects the ESP8266 board
to the given Wi-Fi network and an MQTT broker. It uses the umqttsimple library for MQTT
communication. The ESP connects to Wi-Fi with the SSID= micropython and
password=micropython, and then it connects to the MQTT broker at IP 192.168.43.54 using
the username hhaeiot and password 123123. It sets the client ID to a unique ID for the
device. The ESP subscribes to the topic hello and publishes messages to the topic
notification.
Boot.py File
Main.py
# Complete project details at https://RandomNerdTutorials.com/micropython-programming-with-
esp32-and-esp8266/

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, user=mqtt_user, password=mqtt_pass)
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()

Code Explanation
This code connects an ESP8266 to the MQTT broker and listens for incoming messages on
the topic hello. It handles incoming messages and print the topic and message. It
constantly checks for new messages, when a message is received, it publishes a
confirmation message 'received' to the publishing topic which is notification in this case.
The ESP8266 reconnects if any error occurs.
Main.py File
Verifying the messages on MQTT broker
I then accessed the MQTT broker to verify if the messages were published by ESP#2

Output ESP#1
The output window shows that the connection is successful and then the ESP received
hello messages from the other ESP.
Output ESP#2
uPyCraft Output Window shows that the ESP is successfully connected to the MQTT broker,
It subscribes to Hello Topic and constantly sends messages to it.

MQTT Broker
We can see that the ESP#2 publishes the Hello messages on hello topic. And ESP#1 publishes received
message on Topic Notification after receiving the Hello messages by ESP#2.
Node-Red Server
We can also access the Node-Red Server and view the messages published by both the
ESPs on the debug windows using the following flow.
Conclusion
We were able to successfully install python and uPyCraft. The we uploaded the firmware on
both the ESPs and installed umqttsimple Library. After that, using the boot.py and main.py
we were able to send and receive messages on the MQTT broker. We verified the messages
published by accessing the MQTT Broker and the Node-Red Server

You might also like