Python Programming/GUI/Serial monitor
This tutorial guides you to develop the Arduino serial monitor-like with Tkinter and 3rd libary pySerial.
Prerequisites: Familiar with pySerial library. If you're want to develop the similar serial monitor desktop applications without 3rd serial library like pyserial, you can skip this tutorial.
| Completion status: this resource has reached a high level of completion. |
Display connected serial port in submenu
[edit | edit source]- Displayed connected Serial Ports in submenu
- Print out chosen Serial port on terminal
from tkinter import *
import serial.tools.list_ports
window = Tk()
def chosenSerialPORT(menuParameter, index):
# index of menu start from 1
print("index", index)
print(menuParameter.entrycget(index, 'label')) # Pass in OPTIONS 'label' to get label value
def scanForExistedPorts(menuParameter):
# delete all existed casscade from menu everytime pressing the command
connectedPORTMenu.delete(1, END)
ports = serial.tools.list_ports.comports()
for port in ports:
# Because index of menu start from 1 so index value has to be increase by ports.index(port)+1
connectedPORTMenu.add_command(label = port, command = lambda menuParameter = menuParameter, index=ports.index(port)+1: chosenSerialPORT(menuParameter, index))
menuBar = Menu(window)
window.config(menu=menuBar)
fileSubMenu = Menu(menuBar)
toolsSubMenu = Menu(menuBar)
# List connected PORT
connectedPORTMenu = Menu(toolsSubMenu, postcommand = lambda: scanForExistedPorts(connectedPORTMenu))
# submenu File to import CSV file
menuBar.add_cascade(label = "File", menu=fileSubMenu)
# submenu
menuBar.add_cascade(label = "Tools", menu=toolsSubMenu)
# Import CSV file to draw static chart
fileSubMenu.add_cascade(label = "Open file")
# Tools sub menu
# Display connected COM Port
toolsSubMenu.add_cascade(label = "Ports", menu = connectedPORTMenu, underline = 0)
window.mainloop()
entrycget(self, index, option): Return the resource value of a menu item for OPTION at INDEX.
The result will be like:
index 1
/dev/ttyUSB0 - Seeeduino Nano
Open the chosen Serial port
[edit | edit source]Automatically start the desktop app without previously setting up the serial port.
Update the program in Display connected serial port in submenu with the following code:
import serial, serial.tools.list_ports
def chosenSerialPORT(menuParameter, index):
#close previously opened port
serialObject.close()
chosenPortString = menuParameter.entrycget(index, 'label')
chosenPort = chosenPortString.split(' ')
#As the chosenPort might have name like: /dev/ttyUSB0 - Seeeduino Nano
#so it needs to be splitted to have port /dev/ttyUSB0
serialObject.port = chosenPort[0]
serialObject.open()
print(serialObject.is_open)
# [...]
serialObject = serial.Serial()
Serial monitor to receive data
[edit | edit source]Feature
- List connected serial port
- Choose baudrate (default 9600)
- Then connect to the chosen port with chosen baudrate
- Receive data is printed out on screen
Exception
- Port must be configured before it can be used: When COM port isn't chosen from ``Tools``
- [Errno 13] could not open port /dev/ttyUSB0: [Errno 13] Permission denied: '/dev/ttyUSB0'
- Port is already opened
from tkinter import *
import serial, serial.tools.list_ports
import tkinter.ttk as comboBox
window = Tk()
def chosenSerialPORT(menuParameter, index):
global connectedPORTMenu, serialObject, baudrate
#close previously opened port
serialObject.close()
chosenPortString = menuParameter.entrycget(index, 'label')
chosenPort = chosenPortString.split(' ')
# As the chosenPort might have name like: /dev/ttyUSB0 - Seeeduino Nano
# so it needs to be splitted to have port /dev/ttyUSB0
serialObject.port = chosenPort[0]
def scanForExistedPorts(menuParameter):
global connectedPORTMenu
# delete all existed casscade from menu everytime pressing the command
connectedPORTMenu.delete(1, END)
ports = serial.tools.list_ports.comports()
for port in ports:
#Because index of menu start from 1 so index value has to be increase by ports.index(port)+1
connectedPORTMenu.add_command(label=port, command = lambda menuParameter = menuParameter, index=ports.index(port)+1: chosenSerialPORT(menuParameter, index))
def guiSetup():
global connectedPORTMenu, serialObject, listView
menuBar = Menu(window)
window.config(menu=menuBar)
fileSubMenu = Menu(menuBar)
toolsSubMenu = Menu(menuBar)
#List connected PORT
connectedPORTMenu = Menu(toolsSubMenu, postcommand = lambda: scanForExistedPorts(connectedPORTMenu))
# submenu File to import CSV file
menuBar.add_cascade(label="File", menu=fileSubMenu)
# submenu
menuBar.add_cascade(label="Tools", menu=toolsSubMenu)
# Import CSV file to draw static chart
fileSubMenu.add_cascade(label="Open file")
# Tools sub menu
# Display connected COM Port
toolsSubMenu.add_cascade(label="Ports", menu=connectedPORTMenu, underline=0)
listView = comboBox.Combobox(window, state = "readonly")
listView['values'] = (4800, 9600, 14400, 19200, 38400, 57600, 115200)
listView.set(9600) # Set default value to 9600
listView.grid(row = 0, column = 0)
Button(window, text = "Open serial port", command = openSerialPort).grid(row = 0, column = 1)
serialObject = serial.Serial()
def openSerialPort():
global listView, baudrate, serialObject
baudrate = listView.get()
serialObject.baudrate = baudrate
try:
serialObject.open()
while True:
serial_receive = serialObject.readline()
print(serial_receive)
except Exception as e:
print(e)
# Exception: Port is already open.
connectedPORTMenu, serialObject, listView, baudrate = None, None, None, None
guiSetup()
window.mainloop()
However, this program still has an existing bugs: Freeze app after chosen the serial port (while Trueloop) (Other contributors please feel free to correct this, make sure your updated program is well tested).
Serial monitor to transmit data to the connected device
[edit | edit source]This program has its serial port features like in Serial monitor to receive data, while it allows transmitting data to the connected device on that serial port.
from tkinter import *
import serial, serial.tools.list_ports
import tkinter.ttk as comboBox
window = Tk()
def chosenSerialPORT(menuParameter, index):
global connectedPORTMenu, serialObject, baudrate
#close previously opened port
serialObject.close()
chosenPortString = menuParameter.entrycget(index, 'label')
chosenPort = chosenPortString.split(' ')
#As the chosenPort might have name like: /dev/ttyUSB0 - Seeeduino Nano
#so it needs to be splitted to have port /dev/ttyUSB0
serialObject.port = chosenPort[0]
def scanForExistedPorts(menuParameter):
global connectedPORTMenu
#delete all existed casscade from menu everytime pressing the command
connectedPORTMenu.delete(1, END)
ports = serial.tools.list_ports.comports()
for port in ports:
#Because index of menu start from 1 so index value has to be increase by ports.index(port)+1
connectedPORTMenu.add_command(label=port, command = lambda menuParameter = menuParameter, index=ports.index(port)+1: chosenSerialPORT(menuParameter, index))
def send_words(text):
global serialObject
result = text.get("1.0","end-1c")
serialObject.write(result.encode()) #encode to bytes
text.delete("1.0","end-1c")
def guiSetup():
global connectedPORTMenu, serialObject, listView
menuBar = Menu(window)
window.config(menu=menuBar)
fileSubMenu = Menu(menuBar)
toolsSubMenu = Menu(menuBar)
#List connected PORT
connectedPORTMenu = Menu(toolsSubMenu, postcommand= lambda: scanForExistedPorts(connectedPORTMenu))
#submenu File to import CSV file
menuBar.add_cascade(label="File", menu=fileSubMenu)
#submenu
menuBar.add_cascade(label="Tools", menu=toolsSubMenu)
#Import CSV file to draw static chart
fileSubMenu.add_cascade(label="Open file")
#Tools sub menu
#Display connected COM Port
toolsSubMenu.add_cascade(label="Ports", menu=connectedPORTMenu, underline=0)
listView = comboBox.Combobox(window, state = "readonly")
listView['values'] = (4800, 9600, 14400, 19200, 38400, 57600, 115200)
listView.set(9600) #Set default value to 9600
listView.grid(row=0, column = 0)
Button(window, text = "Open serial port", command = openSerialPort).grid(row=0, column = 1)
serialObject = serial.Serial()
#Text box widget to send data
text = Text(window, width=40, height=1)
text.grid(row=1, column = 0)
button = Button(window, text = "Send", command = lambda: send_words(text))
button.grid(row=1, column = 1)
def openSerialPort():
global listView, baudrate, serialObject
baudrate = listView.get()
serialObject.baudrate = baudrate
try:
#Just open the port to send data
serialObject.open()
except Exception as e:
print(e)
#Exception: Port is already open.
connectedPORTMenu, serialObject, listView, baudrate = None, None, None, None
guiSetup()
window.mainloop()