Skip to content

14. Interfacing

Group Project

The group assignment for this week was to “compare as many tool options as possible”. In our documentation, Angelina Yang and I compared the tools we used, as well as a couple other presented by Neil on the schedule. The link to our group documentation can be found here.

Week Assignment

This week, I worked with Evan Park to setup a MQTT broker, connect to it from a Raspberry Pi Pico W, and send messages from a GUI through this broker to the Raspberry Pi Pico W, ultimately to simply blink an LED.

Thonny IDE

Originally because of a tutorial we were following, Evan Park and I used Thonny IDE for this week’s process, as this IDE works primarily in Micropython, the language the Raspberry Pi Pico W takes which combines many of the benefits of other programming languages. After installing Thonny IDE, I connected it to my Pico W by holding down on the BOOTSEL button on the Pico W while simultaneously plugging it in (through USB) to my computer. I could then add the UF2 file (included in the file download) to the board in my files. This installs Micropython on the board so that I could program it. I could then select this in the bottom right corner as the Port I wanted to use. Later, when I would create my GUI and just wanted the Micropython code to run on the computer, I would reselect “Local Python 3 Thonny’s Python”.

MQTT Tutorials/Setting Up Raspberry Pi Pico W

Originally, Evan and I followed this tutorial which utilized a Raspberry Pi Pico W, Thonny IDE, MQTT, and Node-RED. Hive MQ also had a video walkthrough for this tutorial. Firstly, we connected a Raspberry Pi Pico W to Thonny IDE as explained above. I then ran print("hello, world") in the Thonny IDE embedded command terminal to make sure Micropython was working correctly on the board. Then, I ran these few lines of code in the terminal to connect the Pico W to Wi-Fi (will eventually be run in the code so might as well just put them in the code and then run it):


import network
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("SSID", "Wi-Fi password")

*Note: insert Wi-Fi name where “SSID” is, and that Wi-Fi’s password for “Wi-Fi password” After eventually getting this to work, the Wi-Fi was connected.

I then had to setup the libraries and code to actually connect to the MQTT broker. I first installed used pip install upip as the tutorial said that I needed to use UPIP to install a library. For a while, I got confused because I read online that UPIP is outdated, and the newer version is MIP. I also installed mip, and tried both for upip.install('micropython-umqtt.robust). I was not completely sure what this does, nor what each of the components in this line did individually (other than install of course), but I tried this using upip and mip, and ofr umqtt.robust and umqtt.simple, another thing the tutorial said I would need. I also installed micropython-upip, as well as micropython-umqtt.robust and micropython-umqtt.simple in manage packages under tools. With some combination of these (I am still not entirely sure what), I could have the line of code from umqtt.simple import MQTT which would import this aspect of the library, allowing the Pi to connect to a MQTT broker.

MQTT Broker

Following along with the tutorial, we originally both created our own MQTT servers using Hive MQ, but eventually found this to be to complicated and just used the Fab Academy MQTT server. To connect to the Fab Academy MQTT server, it was very simple, as the username and password were both “fabacademy” and the server name was “mqtt.fabcloud.org” (I am only sharing this because it was already publicly accessible information, do not share this information if you wish your server to be private).

Pico Board

In order to allow this Pico to display its communication with other devices using the MQTT server, I created a board for it, which would include many output headers for I2C, a button, and an LED. This is the board looked like in KiCAD:

After I milled and soldered it:

Button

First, I wanted to publish an indicating message when the button was pressed. To do this, I used this code:


**button code**

To ensure that these messages were being published and for troubleshooting, I would connect to the network simply through the command terminal, by inputting this line: mosquitto_sub -h mqtt.fabcloud.org -p 1883 -u fabacademy -P fabacademy -t fabacademy The -h is the “host” or server, -p is the port, -u is the username, -P is the password, and -t is the topic to subscribe to. After sucessfully subscribing to the same topic I published to in my Pico code, I saw the messages pop up as I pushed the button on the board.

LED

Next, I wanted to communicate from the computer to the board. To display this, I would use the on-board LED. To do this I used a GUI.

GUI

I was tempted to try Node Red at first as this is what the tutorial used, but I ran into complications trying to install Node-RED, and thought it would be interesting to create a GUI myself anyway. Thus, I decided to do it all in Thonny IDE. Setting up the GUI was not the difficult part of this, though. Receiving a message was what I was mostly confused about. Because I am currently taking AP Computer Science Principles, I have had some experience using the library Tkinter, and understood what it is and what is does. Initially, I still used Copilot to setup a basic button using Tkinter, and I would learn commands using the library from there. I did not know the functions to receive a message using MQTT though, nor how it worked. After much trial and error, I used Connor Cruz’s code, as he had already blinked an LED using a GUI. This is what the code for the computer looked like:


import tkinter as tk
import paho.mqtt.publish as publish
import paho.mqtt.client as mqtt

latestMessages = ["", "", "", "", ""]

def publishMessage():
    host = hostInput.get()
    topic = topicInput.get()
    msg = messageInput.get()
    port = portInput.get()
    usrname = usernameInput.get()
    pswd = passwordInput.get()
    print(host, topic, msg, port, usrname, pswd)
    publish.single(topic, msg, hostname=host, port=int(port), auth={'username': usrname, 'password': pswd})

def defaultSet():
    hostInput.delete(0, tk.END)
    hostInput.insert(0, "mqtt.fabcloud.org")
    topicInput.delete(0, tk.END)
    topicInput.insert(0, "fabacademy")
    messageInput.delete(0, tk.END)
    messageInput.insert(0, "LED ON")
    portInput.delete(0, tk.END)
    portInput.insert(0, "1883")
    usernameInput.delete(0, tk.END)
    usernameInput.insert(0, "fabacademy")
    passwordInput.delete(0, tk.END)
    passwordInput.insert(0, "fabacademy")

def onConnect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected to broker")
        client.subscribe("fabacademy")
    else:
        print("Connection to broker failed")

def onMessage(client, userdata, msg):
    global latestMessages
    message = msg.payload.decode()
    print("Received message:", message)
    latestMessage = message

    for i in range(0, 4):
        latestMessages[i] = latestMessages[i + 1]

    latestMessages[4] = message
    outputDisplay.delete(1.0, tk.END)
    for i in latestMessages:
        if i == "":
            continue
        outputDisplay.insert(tk.END, i + "\n")

    if latestMessage == "Button Pressed!":
        buttonPressed.config(text="BUTTON PRESSED")
        buttonPressed.config(bg="lightgreen")
    elif latestMessage == "Button Not Pressed!":
        buttonPressed.config(text="BUTTON NOT PRESSED")
        buttonPressed.config(bg="red")

root = tk.Tk()
root.title("Connor Cruz 3.0 Interface")

inputFrame = tk.Frame(root)
inputFrame.pack(side=tk.LEFT, padx=10)

hostLabel = tk.Label(inputFrame, text="Host:")
hostLabel.grid(row=0, column=0)
hostInput = tk.Entry(inputFrame, width=50)
hostInput.grid(row=0, column=1)

topicLabel = tk.Label(inputFrame, text="Topic:")
topicLabel.grid(row=1, column=0)
topicInput = tk.Entry(inputFrame, width=50)
topicInput.grid(row=1, column=1)

messageLabel = tk.Label(inputFrame, text="Message:")
messageLabel.grid(row=2, column=0)
messageInput = tk.Entry(inputFrame, width=50)
messageInput.grid(row=2, column=1)

portLabel = tk.Label(inputFrame, text="Port:")
portLabel.grid(row=3, column=0)
portInput = tk.Entry(inputFrame, width=50)
portInput.grid(row=3, column=1)

usernameLabel = tk.Label(inputFrame, text="Username:")
usernameLabel.grid(row=4, column=0)
usernameInput = tk.Entry(inputFrame, width=50)
usernameInput.grid(row=4, column=1)

passwordLabel = tk.Label(inputFrame, text="Password:")
passwordLabel.grid(row=5, column=0)
passwordInput = tk.Entry(inputFrame, width=50)
passwordInput.grid(row=5, column=1)

defaultButton = tk.Button(inputFrame, text="Connor Cruz 3.0 Default", command=defaultSet, width=50)
defaultButton.grid(row=6, column=0, columnspan=2)

publishButton = tk.Button(inputFrame, text="Publish", command=publishMessage, width=50)
publishButton.grid(row=7, column=0, columnspan=2)

outputFrame = tk.Frame(root)
outputFrame.pack(side=tk.RIGHT, padx=10, pady=10)
outputLabel = tk.Label(outputFrame, text="Server Output (Most Recent Messages):")
outputLabel.grid(row=0)
outputDisplay = tk.Text(outputFrame, width=50, height=5)
outputDisplay.grid(row=1)

buttonFrame = tk.Frame(outputFrame)
buttonFrame.grid(row=2, pady=10)

buttonPressed = tk.Label(buttonFrame, width=58, height=5, text="BUTTON NOT PRESSED", bg="red")
buttonPressed.pack()

client = mqtt.Client()
client.on_connect = onConnect
client.on_message = onMessage

client.username_pw_set(username="fabacademy", password="fabacademy")

client.connect("mqtt.fabcloud.org", 1883)

client.loop_start()

root.mainloop()

Since I was using his code for the computer, I also had to use his code for the Pico, as his code used specific variables. This is the code for the Pico:


import network
import time
from machine import Pin
from umqtt.simple import MQTTClient

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('SSID', 'SECURITY KEY')

time.sleep(5)
print('Connected:', wlan.isconnected())

mqtt_server = 'mqtt.fabcloud.org'
broker_port = 1883
client_id = 'fabstudent'
username = 'fabacademy'
password = 'fabacademy'
topic = 'fabacademy'

client = MQTTClient(client_id, mqtt_server, port=broker_port,
        user=username, password=password, keepalive=3600)

ledOn = False
ledPin = Pin(27, Pin.OUT)
buttonPin = Pin(0, Pin.IN)

def mqtt_connect():
    try:
        client.connect()
        print('Broker connected successfully')
    except Exception as e:
        print('Failed broker connection: ', e)

def reconnect():
    print('Reconnecting to broker')
    time.sleep(5)
    machine.reset()

def publish(topic, msg):
    try:
        client.publish(topic, msg)
        print(f'Published {msg} to {topic}')
    except Exception as e:
        print('Error publishing to topic:', e)

def subscribe(topic):
    try:
        client.subscribe(topic)
        print('Subscribed to topic:', topic)
    except Exception as e:
        print('Error subscribing to topic:', e)

def callback(topic, msg):
    global ledOn
    print(f'Received message on topic: {topic}; Message: {msg}')
    if msg == b'LED ON':
        ledOn = True

def ledBlink():
    global ledOn
    client.check_msg()
    if ledOn:
        print('ON')
        ledPin.value(1)
        time.sleep(0.5)
        ledPin.value(0)
        ledOn = False

def buttonPress():
    buttonPressed = buttonPin.value()
    if buttonPressed:
        publish(topic, 'Button Pressed!')

try:
    mqtt_connect()
    client.set_callback(callback)
except OSError as e:
    reconnect()

subscribe(topic)

while True:
    #Uncomment one call depending on input or output
    ledBlink()
    #buttonPress()
    time.sleep(0.1)

This is a video of that working:

I then created my own, simplified code which blinks the LED for a duration of time determined by an input on the GUI:


import tkinter as tk
topic = 'fabacademy'
import paho.mqtt.client as mqtt

client = mqtt.Client()

client.username_pw_set(username="fabacademy", password="fabacademy")
client.connect("mqtt.fabcloud.org", 1883)

client.loop_start()

def publish():
    # Function to handle the button click
    # Retrieves the text from entry widget and prints it
    seconds = text_entry.get()
    print(f"Published to {topic}:", seconds)
    client.publish(topic, seconds)

# Create the main window
root = tk.Tk()
root.title("LED Time")

# Create a label for instructions
label = tk.Label(root, text="Seconds (enter 'off' to turn LED off):")
label.pack(pady=(10, 0))  # Add some vertical padding

# Create a text entry widget
text_entry = tk.Entry(root, width=5)
text_entry.pack(pady=10)

# Create a submit button
submit_button = tk.Button(root, text="Publish", command=publish)
submit_button.pack(pady=(0, 10))

# Start the GUI event loop
root.mainloop()

Here is a video of that code working:

Week Reflection

This week I learned about interfacing a board or chip to a computer or other device through an MQTT broker. I also came to understand that there are many ways of doing this, MQTT being one of them. Of course, many (if not all) of these methods involve the use of Wi-Fi, but this knowledge nonetheless significantly expands my capabilities with a microchip/microcontroller. This week is arguably one of the most valuable if taken advantage of properly.

File Downloads

The files involved in the processes included in this week’s documentation can be downloaded here.


Last update: June 26, 2024