# Project#13 - Arduino UNO # Information - We are going to build on project#5, and we're going to use a run-pf-the-mill Arduino UNO # in place of the RPI_no_PRI. Why? Ecause I want to show you that you can use pyserial with most microcontrollers. # I've used it with raspberry Picos, Arduino products (Many of them), and ESP32 devices. So how are we building on # project#5? We're going to create a four-channel GUI based controller. For this project, you an use LEDs in place # of the relays, or you can purchase a relay board like this one: # Link: https://www.amazon.ca/s?k=4-channel+relay+module+5v&gclid=EAIaIQobChMIwtbUifz0_AIVMgIGAB22bgxuEAAYASAAEgLU7PD_BwE&hvadid=604749252392&hvdev=c&hvlocphy=9000685&hvnetw=g&hvqmt=b&hvrand=7665906173760674459&hvtargid=kwd-1234900581594&hydadcr=6718_13264625&tag=googcana-20&ref=pd_sl_3xuo4245rk_b # Just search "5v 4CH relay board'. # The relay board needs to be a 5v one, and not a 12v one. There will be 6 pins. 5v/GND/RLY1/2/3/4 # If you want to create awesome GUIs, I highly recommend this tutorial: https://www.youtube.com/watch?v=YXPyB4XeYLA from tkinter import * # Import GUY module import time # For delays import serial # For microcontroller communication root = Tk() # Needs to be first to great the GUI window root.title("RELAY API PROGRAM - Syntronic") # Give the GUI a title root.geometry('275x200') # Frame the GUI try: MCU = serial.Serial(port='COM10', baudrate=115200, timeout=0.01) # Establish Comms time.sleep(1) # Wait for one second except: print('System Locked - Cannot communicate with MCU. Close this GUI, connect to MCU and restart program') while True: # Forever loop. Close the program and start again. Check connection to the MCU pass # Do nothing def write_read(x): # This function sends relay instructions to the Arduino UNO MCU.write(bytes(x, 'utf-8')) # Unicode Transformation Format - 8 bits. Write an 8-bit value to the MCU time.sleep(0.2) # Wait 200ms def buttonclick(number): # This function is called when any GUI button is pressed. # The 'number' value tells the function what to to. global Relay1_Entry # Relay1-Relay4_Entry windows are declared as globals here so that we can access them. global Relay2_Entry global Relay3_Entry global Relay4_Entry # This function takes care of all buttonpresses in the ENTER SETTINGS AREA of the GUI if number == 1: # If the relay1 button was pushed, execute the following x = '1' # x holds the command to be sent to the MCU. Send integer '1' to the MCU. It will receive ASCII write_read(x) # write x to the Arduino. # Call the write_read() function to tell the Arduino to toggle the state of the relative relay (1 in this case) value = Relay1_Entry.get() # Get the current value from the relay#1 entry window. Relay1_Entry.configure(state='normal') # Set the window state to normal, so that we can change what is in it Relay1_Entry.delete(0, END) # Clear the window if value == 'OFF': # IF the previous value was 'OFF' Relay1_Entry.insert(0, 'ON') # Set to 'ON" else: # If the previous state wasn't 'OFF', then it was 'ON' If so, change to the opposite 'OFF' Relay1_Entry.insert(0, 'OFF') # Set to 'OFF' Relay1_Entry.configure(state='disable') # Disable the ability to manually enter anything in this window elif number == 2: # The remainder of this function is the same as above. It takes the same steps for each relay x = '2' # If the relay#2 button was press, it will send over a value of 2 to the Arduino. write_read(x) # Check out the bottom of this function. We call an 'ALL RELAYS OFF!' button value = Relay2_Entry.get() Relay2_Entry.configure(state='normal') Relay2_Entry.delete(0, END) # Clear the window if value == 'OFF': Relay2_Entry.insert(0, 'ON') # Pre-enter else: Relay2_Entry.insert(0, 'OFF') # Pre-enter Relay2_Entry.configure(state='disable') elif number == 3: # If fault entry button was selected, execute the following x = '3' # x holds the command to be sent to the MCU write_read(x) # write x to the MCU value = Relay3_Entry.get() Relay3_Entry.configure(state='normal') Relay3_Entry.delete(0, END) # Clear the window if value == 'OFF': Relay3_Entry.insert(0, 'ON') # Pre-enter else: Relay3_Entry.insert(0, 'OFF') # Pre-enter Relay3_Entry.configure(state='disable') elif number == 4: # If fault entry button was selected, execute the following x = '4' # x holds the command to be sent to the MCU write_read(x) # write x to the MCU value = Relay4_Entry.get() Relay4_Entry.configure(state='normal') Relay4_Entry.delete(0, END) # Clear the window if value == 'OFF': Relay4_Entry.insert(0, 'ON') # Pre-enter else: Relay4_Entry.insert(0, 'OFF') # Pre-enter Relay4_Entry.configure(state='disable') elif number == 5: # If button#5 is pressed 'ALL RELAYS OFF!", then do the following x = '5' # INT 5 is the value that turns all relays off when send to the Arduino write_read(x) # write x to the MCU Relay1_Entry.configure(state='normal') # Allows for us to edit all four relay entry windows at once Relay2_Entry.configure(state='normal') Relay3_Entry.configure(state='normal') Relay4_Entry.configure(state='normal') Relay1_Entry.delete(0, END) # Clear all four relay entry windows Relay2_Entry.delete(0, END) Relay3_Entry.delete(0, END) Relay4_Entry.delete(0, END) Relay1_Entry.insert(0, 'OFF') # Set them all to 'OFF' Relay2_Entry.insert(0, 'OFF') Relay3_Entry.insert(0, 'OFF') Relay4_Entry.insert(0, 'OFF') Relay1_Entry.configure(state='disable') # Disable editing to all four entry windows. Relay2_Entry.configure(state='disable') Relay3_Entry.configure(state='disable') Relay4_Entry.configure(state='disable') # In this area, we'll create our GUI Spacer_Label0 = Label(root, text='') # This is just an empty label that acts as a spacer. Name_Label = Label(root, text='TOGGLE RELAY STATES...') # This is the label/name at the top of the GUI Name_Label.configure(justify='left') # Left justify the above label Spacer_Label1 = Label(root, text='') # Create another spacer labelled Spacer_label1 Relay1 = Button(root, text= 'RELAY#1', padx=5, pady=10, command=lambda: buttonclick(1)) # Create this button and send 1 to the buttonclick function when pressed. Relay2 = Button(root, text='RELAY#2', padx=5, pady=10, command=lambda: buttonclick(2)) # Create the relay#2 button Relay3 = Button(root, text='RELAY#3', padx=5, pady=10, command=lambda: buttonclick(3)) # Do the same for the relay3/relay4 buttons Relay4 = Button(root, text='RELAY#4', padx=5, pady=10, command=lambda: buttonclick(4)) Relay_OFF = Button(root, text='ALL RELAYS OFF!', padx=20, pady=10, command=lambda: buttonclick(5)) # Create the relay-off button Relay1_Entry = Entry(root, width=5, borderwidth=5) # Here we'll create the relay entry windows, which will hold states Relay1_Entry.insert(0,'OFF') # All will be set to 'OFF' as a starting point. Relay1_Entry.configure(state='disable') # Disable the ability to change what is in the window Relay2_Entry = Entry(root, width=5, borderwidth=5) # Do this for all four relay entry windows Relay2_Entry.insert(0,'OFF') # Pre-enter Relay2_Entry.configure(state='disable') Relay3_Entry = Entry(root, width=5, borderwidth=5) Relay3_Entry.insert(0,'OFF') # Pre-enter Relay3_Entry.configure(state='disable') Relay4_Entry = Entry(root, width=5, borderwidth=5) Relay4_Entry.insert(0,'OFF') # Pre-enter Relay4_Entry.configure(state='disable') # GRID SETTINGS # Allocate the area for the operator name and email inputs. Spacer_Label0.grid(row=0,column=0) # Set the coordinates for the first spacer label Name_Label.grid(row=1,column=0,columnspan=4) # Set the coordinates for the GUI name and set it across all columns Spacer_Label1.grid(row=2,column=0) # Set the row and column coordinates for all labels,windows, and buttons Relay1.grid(row=3,column=0) Relay2.grid(row=3,column=1) Relay3.grid(row=3,column=2) Relay4.grid(row=3,column=3) Relay1_Entry.grid(row=4, column=0, padx=5, pady=5) Relay2_Entry.grid(row=4, column=1, padx=5, pady=5) Relay3_Entry.grid(row=4, column=2, padx=5, pady=5) Relay4_Entry.grid(row=4, column=3, padx=5, pady=5) Relay_OFF.grid(row=5, column=0,columnspan=4, padx=5, pady=5) root.mainloop() # Display everything on the screen and loop until you exit