And here are my 3 created GUI images (800 x 480px) showing the different buttons status:
GUI with button in the default status:
GUI with the buttons in "Clicked status":
and the third image showing the buttons in activated/ON status: all my button are 60px x 60px and are in this grid coordinate (X , Y):
Botton1 (72, 20)
Botton2 (336, 20)
Botton3 (420, 20)
Botton4 (580, 20)
Botton5 (72, 89)
Botton6 (336, 89)
Botton7 (420, 89)
Botton8 (580, 89)
Botton9 (74, 158)
Botton10 (245, 226)
Botton11 (420, 155)
Botton12 (580, 155)
Botton13 (74, 222)
Botton14 (370, 420)
Botton15 (420, 222)
Botton16 (580, 222)
Any idea how I can modify my code below to have the buttons on the GUI change its image from its 60 x 60px area to the images of the background images depending on the button status?
Here is my current code for the tkinter GUI with conventional buttons:Any help with this would be appreciated...
GUI with button in the default status:
GUI with the buttons in "Clicked status":
and the third image showing the buttons in activated/ON status: all my button are 60px x 60px and are in this grid coordinate (X , Y):
Botton1 (72, 20)
Botton2 (336, 20)
Botton3 (420, 20)
Botton4 (580, 20)
Botton5 (72, 89)
Botton6 (336, 89)
Botton7 (420, 89)
Botton8 (580, 89)
Botton9 (74, 158)
Botton10 (245, 226)
Botton11 (420, 155)
Botton12 (580, 155)
Botton13 (74, 222)
Botton14 (370, 420)
Botton15 (420, 222)
Botton16 (580, 222)
Any idea how I can modify my code below to have the buttons on the GUI change its image from its 60 x 60px area to the images of the background images depending on the button status?
Here is my current code for the tkinter GUI with conventional buttons:
Code:
import tkinter as tkimport RPi.GPIO as GPIOimport threadingimport timefrom datetime import datetimeimport queuefrom apscheduler.schedulers.background import BackgroundSchedulerimport loggingimport adafruit_dhtimport boardimport subprocess# Variable to keep track of the music processmusic_process = None# Function to play or stop musicdef toggle_music(): global music_process # Path to the audio file you want to play audio_file = "/home/microgreen/Music/music.mp3" # Replace with your actual file path if music_process is None or music_process.poll() is not None: # Music is not playing, so start it with looping in the background music_process = subprocess.Popen( ["vlc", "--intf", "dummy", "--loop", audio_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) play_button.config(text="Stop", bg="red") # Change button text to "Stop Music" else: # Music is playing, so stop it music_process.terminate() # Terminate the VLC process music_process = None play_button.config(text="Play", bg="green") # Change button text back to "Play Music"# Enable detailed logginglogging.basicConfig(level=logging.DEBUG, format='%(message)s')# GPIO SetupGPIO.setmode(GPIO.BCM)GPIO.setwarnings(False)# DHT22 Sensor SetupDHT_SENSOR = adafruit_dht.DHT22(board.D4) # Replace with actual GPIO pin# Define GPIO pinspins = { "LED Shelf #1 & 2": 17, "LED Shelf #3 & 4": 18, "Water Sprayer": 25, "Fans": 5, "Water Shelf 1": 27, "Water Shelf 2": 22, "Water Shelf 3": 23, "Water Shelf 4": 24}# Set up GPIO as outputfor pin in pins.values(): GPIO.setup(pin, GPIO.OUT) GPIO.output(pin, GPIO.HIGH) # OFF state for relays# Initialize GUIwin = tk.Tk()win.title("Microgreens Farm Controller")win.geometry("800x480")# Default colors for OFF stateDEFAULT_COLORS = { 17: "#ffeb3b", 18: "#ffeb3b", 5: "#FFA500", 25: "#87CEEB",}# Checkbox control variablesshelf_enabled_vars = {pins[f"Water Shelf {i}"]: tk.IntVar() for i in range(1, 5)}# Timer valuestimer_values = {pins[f"Water Shelf {i}"]: tk.StringVar() for i in range(1, 5)}def start_timer(pin, button, duration, label): time.sleep(duration) GPIO.output(pin, GPIO.HIGH) button.config(text=f"{label} OFF", bg="#87CEFA")def toggle_water_shelf(pin, button, label): print(f"Toggling water shelf {label} with pin {pin}") if shelf_enabled_vars[pin].get(): if GPIO.input(pin): GPIO.output(pin, GPIO.LOW) button.config(text=f"{label} ON", bg="#2ecc71") print(f"Water shelf {label} turned ON") try: duration = int(timer_values[pin].get()) except ValueError: duration = 10 threading.Thread(target=start_timer, args=(pin, button, duration, label), daemon=True).start() logging.debug(f"Water Shelf {label} turned ON for {duration} seconds.") else: GPIO.output(pin, GPIO.HIGH) button.config(text=f"{label} OFF", bg="#87CEFA") logging.debug(f"Water Shelf {label} turned OFF.") else: logging.debug(f"Watering not enabled for {label}.")# Scheduler variablesday_vars = {day: tk.IntVar() for day in ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]}hour_vars = {hour: tk.IntVar() for hour in range(24)}schedule_shelf_vars = {pins[f"Water Shelf {i}"]: tk.IntVar() for i in range(1, 5)}# Light cycle settingsled_on_durations = {pin: tk.StringVar(value="16") for pin in [17, 18]}led_off_durations = {pin: tk.StringVar(value="8") for pin in [17, 18]}# Scheduler setupscheduler = BackgroundScheduler()scheduler.start()def apply_led_schedule(pin, button, label): """Applies the light schedule for the given LED.""" try: on_duration = int(led_on_durations[pin].get()) off_duration = int(led_off_durations[pin].get()) except ValueError: logging.error("Invalid duration input. Using default 12 ON / 6 OFF.") on_duration, off_duration = 12, 6 def turn_on(): if GPIO.input(pin) == 0: # Only turn ON if it was previously ON GPIO.output(pin, GPIO.LOW) button.config(text=f"{label} ON", bg="#2ecc71") logging.info(f"{label} turned ON") scheduler.add_job(turn_off, 'interval', hours=on_duration, id=f"led_off_{pin}") def turn_off(): GPIO.output(pin, GPIO.HIGH) button.config(text=f"{label} OFF", bg=DEFAULT_COLORS[pin]) logging.info(f"{label} turned OFF") scheduler.add_job(turn_on, 'interval', hours=off_duration, id=f"led_on_{pin}") turn_on()# Temperature & Humidity Sensor Frametemp_frame = tk.Frame(win)temp_frame.pack(side="top", pady=0)temp_label = tk.Label(temp_frame, text="Temp: --", font=("Arial", 12))temp_label.pack(side="left", padx=5)humidity_label = tk.Label(temp_frame, text="Humidity: --", font=("Arial", 12))humidity_label.pack(side="right", padx=5)"""Reads temperature and humidity from DHT22 and updates the GUI."""def update_temp_humidity(): try: # Read values from the DHT22 sensor temperature = DHT_SENSOR.temperature humidity = DHT_SENSOR.humidity except RuntimeError as error: logging.error(f"Sensor error: {error}") temperature, humidity = None, None if humidity is not None and temperature is not None: # Update the labels with the sensor readings temp_label.config(text=f"Temp: {temperature:.1f}\u00B0C") humidity_label.config(text=f"Humidity: {humidity:.1f}%") else: # If there is an error with the sensor, display "--" temp_label.config(text="Temp: --") humidity_label.config(text="Humidity: --") # Schedule the next update in 5 seconds win.after(5000, update_temp_humidity)# Start the first update when the program startsupdate_temp_humidity()def toggle_device(pin, button, label): """Manually toggles LED state and cancels the schedule if turned OFF manually.""" if GPIO.input(pin): GPIO.output(pin, GPIO.LOW) button.config(text=f"{label} ON", bg="#2ecc71") else: GPIO.output(pin, GPIO.HIGH) button.config(text=f"{label} OFF", bg=DEFAULT_COLORS.get(pin, "#ffeb3b")) scheduler.remove_job(f"led_off_{pin}", jobstore=None) scheduler.remove_job(f"led_on_{pin}", jobstore=None)# Main layoutframe = tk.Frame(win)frame.pack(expand=True, fill="both", pady=1)left_frame = tk.Frame(frame)left_frame.grid(row=0, column=0, padx=12, sticky="n")LED_frame = tk.Frame(frame)LED_frame.grid(row=0, column=1, padx=0, pady=15, sticky="n")water_shelf_frame = tk.Frame(frame)water_shelf_frame.grid(row=0, column=2, padx=5, sticky="n")# Create a button to toggle music playbackplay_button = tk.Button(left_frame, text="Play", command=toggle_music, width=2, height=0, bg="green")play_button.grid(row=2, column=3, padx=0, pady=10, sticky="n")def create_toggle_button(label, pin, row): button = tk.Button(left_frame, text=label + " OFF", bg=DEFAULT_COLORS.get(pin, "#ffeb3b"), width=16, height=2) button.config(command=lambda: toggle_device(pin, button, label)) button.grid(row=row, column=0, padx=2, pady=2, sticky="w") return buttoncontrols = [ ("LED Shelf #1 & 2", 17), ("LED Shelf #3 & 4", 18), ("Water Sprayer", 25), ("Fans", 5),]for i, (label, pin) in enumerate(controls): create_toggle_button(label, pin, i)def create_water_shelf_button(label, pin, row): button = tk.Button(water_shelf_frame, text=label + " OFF", bg="#87CEFA", width=16, height=2) button.config(command=lambda: toggle_water_shelf(pin, button, label)) button.grid(row=row, column=0, padx=2, pady=2, sticky="w") shelf_checkbox = tk.Checkbutton(water_shelf_frame, text="Enable Watering", variable=shelf_enabled_vars[pin]) shelf_checkbox.grid(row=row, column=1, padx=2, pady=5, sticky="w") timer_entry = tk.Entry(water_shelf_frame, textvariable=timer_values[pin], width=5) timer_entry.grid(row=row, column=2, padx=2, pady=5, sticky="e") timer_values[pin].set("10") timer_label = tk.Label(water_shelf_frame, text="Seconds") timer_label.grid(row=row, column=3, padx=2, pady=2, sticky="e") return buttonwater_shelf_buttons = {}for i in range(1, 5): water_shelf_buttons[pins[f"Water Shelf {i}"]] = create_water_shelf_button(f"Water Shelf {i}", pins[f"Water Shelf {i}"], i)# Scheduler Framescheduler_frame = tk.Frame(win)scheduler_frame.pack(side="top", pady=0)# Scheduler (Shelves Section)shelves_frame = tk.Frame(win)shelves_frame.pack(side="top", pady=0)# Scheduler (Days Section)days_frame = tk.Frame(win)days_frame.pack(side="top", pady=0)# Scheduler (Hours Section)hours_frame = tk.Frame(win)hours_frame.pack(side="top", pady=0)# Scheduler (Set Schedule Button)setButton_frame = tk.Frame(win)setButton_frame.pack(side="top", pady=0)# Function to toggle devicesdef toggle_device(pin, button, label): if GPIO.input(pin): GPIO.output(pin, GPIO.LOW) button.config(text=f"{label} ON", bg="#2ecc71") else: GPIO.output(pin, GPIO.HIGH) button.config(text=f"{label} OFF", bg=DEFAULT_COLORS.get(pin, "#ffeb3b")) def schedule_watering(): selected_days = [day for day, var in day_vars.items() if var.get() == 1] selected_hours = [hour for hour, var in hour_vars.items() if var.get() == 1] selected_shelves = [shelf for shelf, var in schedule_shelf_vars.items() if var.get() == 1] # Create popup window to confirm schedule schedule_popup = tk.Toplevel(win, padx=20, pady=10) schedule_popup.title("Schedule Confirmation") tk.Label(schedule_popup, text="Scheduled Confirmation", font=("Arial", 14), padx=30, pady=5).pack() tk.Label( schedule_popup, text=f"Scheduled: {', '.join([f'Water Shelf {list(pins.keys())[list(pins.values()).index(s)].split()[-1]} ({timer_values[s].get()}s)' for s in selected_shelves])}").pack() tk.Label(schedule_popup, text=f"Scheduled Days: {', '.join(selected_days)}").pack() tk.Label(schedule_popup, text=f"Scheduled Hours: {', '.join(map(str, selected_hours))}").pack() for day in selected_days: for hour in selected_hours: for shelf in selected_shelves: shelf_label = f"Water Shelf {list(pins.values()).index(shelf)}" # Get correct label scheduler.add_job( lambda s=shelf, l=shelf_label: toggle_water_shelf(s, water_shelf_buttons[s], l), 'cron', day_of_week=day.lower(), hour=hour, minute=0 )tk.Label(scheduler_frame, text="Watering Schedule", font=("Arial", 12, "bold")).grid(row=0, column=0, columnspan=8, sticky="n")# Days selectiontk.Label(days_frame, text="Days:").grid(row=1, column=0, sticky="n")for i, (day, var) in enumerate(day_vars.items()): tk.Checkbutton(days_frame, text=day, variable=var).grid(row=1, column=i+1, sticky="n")# Hours selection with AM/PM labelstk.Label(hours_frame, text="Hours:").grid(row=2, column=0, sticky="n")hour_vars = {hour: tk.IntVar() for hour in range(24)}for i, (hour, var) in enumerate(hour_vars.items()): am_pm_label = f"{hour % 12 if hour % 12 else 12}{'am' if hour < 12 else 'pm'}" tk.Checkbutton(hours_frame, text=am_pm_label, variable=var).grid(row=2 + (i // 12), column=(i % 12) + 1, sticky="n")# Shelves selectiontk.Label(shelves_frame, text="Shelves:").grid(row=3, column=0, sticky="w")for i, (shelf, var) in enumerate(schedule_shelf_vars.items()): tk.Checkbutton(shelves_frame, text=f"Shelf {i+1}", variable=var).grid(row=3, column=i+1, sticky="n")# Schedule Buttontk.Button(setButton_frame, text="Set Schedule", bg="green", fg="white", command=schedule_watering).grid(row=1, column=2, columnspan=8, pady=0)def enqueue_event(shelf): logging.debug(f"Enqueueing event for {shelf}") print(f"Watering {shelf} for the scheduled duration.") # LED Controlsfor i, (label, pin) in enumerate([("LED Shelf #1 & 2", 17), ("LED Shelf #3 & 4", 18)]): button = tk.Button(left_frame, text=label + " OFF", bg=DEFAULT_COLORS[pin], width=16, height=2) button.config(command=lambda p=pin, b=button, l=label: toggle_device(p, b, l)) button.grid(row=i, column=0, padx=2, pady=2, sticky="w") tk.Label(left_frame, text="ON").grid(row=i, column=1) tk.Entry(left_frame, textvariable=led_on_durations[pin], width=2).grid(row=i, column=2) tk.Label(left_frame, text="OFF").grid(row=i, column=3) tk.Entry(left_frame, textvariable=led_off_durations[pin], width=2).grid(row=i, column=4) tk.Label(left_frame, text="Hrs").grid(row=i, column=5, pady=13) tk.Button(left_frame, text="Set", command=lambda p=pin, b=button, l=label: apply_led_schedule(p, b, l)).grid(row=i, column=6, padx=1)# Exit program functiondef stopProgram(): scheduler.shutdown() GPIO.cleanup() win.quit()tk.Button(win, text="Exit", bg="#c0392b", fg="white", width=15, height=1, command=stopProgram).pack(side="bottom", pady=2)win.mainloop()
Statistics: Posted by papagino — Fri Apr 04, 2025 9:09 pm