OK but I would like the scheduler to only simulate button press for the watering shelves, and not actually controlling GPIO pins. The reason for this is that there are watering duration timers (ex: 10s) that will change on a regular basis depending on what type of microgreens needs watering, some take more water than others.Not a simple thing.
The easy part is the architecture: whenever background activities need to be done, then it is needed to isolate these tasks from the tkinter event queue 'mainloop'. The win.after(...) method allows to set up a periodical call which runs in tkinter context. A queue.Queue is used to isolate the background task from the tkinter context. The background runs in a thread and just sends events to the queue.Queue which are then evaluated in the tkinter context.
The background for the problem can be a scheduler. I usually use apscheduler package which allows cron type triggers which almost perfect match the day, hour pattern from your GUI. apscheduler creates threads on its own. I'd setup plenty of jobs, for each shelf, day, hour. This keeps processing in the tkinter context simple.
The data structures of your existing program do not perfectly match the needs of such a structure. For the scheduler checkboxes, there should be IntVar associated, see the sample. See also the numbering of the day, cron style is 0,1,2... for mon,tue, wed, thu ... ; you have sun first.Code:
import queueimport tkinter as tk# install apscheduler packageimport apscheduler.schedulers.backgroundscheduler = apscheduler.schedulers.background.BackgroundScheduler()eventqueue = queue.Queue()activation_labels = [ "Water Shelf 1", "Water Shelf 2", "Water Shelf 3", "Water Shelf 4", ]activation_pins = [ 27, 22, 23, 24 ]# --- create the scheduler jobsjob_id = 0for shelf in range(4): for day_of_week in range(7): for hour in range(24): event = {"shelf": shelf, "day_of_week": day_of_week, "hour": hour, } scheduler.add_job(lambda e=event: eventqueue.put(e), 'cron', day_of_week =day_of_week, hour=hour, id= f'job_id_{job_id}') job_id += 1print(job_id)scheduler.start()win = tk.Tk()win.title("Microgreens Farm Controller with Scheduler")win.geometry("800x480")# --- in your code, create intvar for each of the checkboxes.# watering schedule day checkbox variables. These are sorted mon,tue,...sunday = [ tk.IntVar(win, 0) for i in range(7)]# watering schedule hour checkbox variableshour = [ tk.IntVar(win, 0) for i in range(24)]# watering schedule shelf checkbox variablesschedule_shelf = [tk.IntVar(win, 0) for i in range(4)]# watering enable shelf checkbox variablesactivation_shelf = [tk.IntVar(win, 0) for i in range(4)]# the buttons for the shelf (needed to set the label text)button_shelf = [tk.Button(win, text=activation_labels[i]).pack(pady=5) for i in range(4)]# --- the existing callback for the shelf button.def toggle_water_shelf(pin, button, label): # use current source code pass# --- a time called tk callbackdef tk_callback(): while True: try: # read the event from background scheduler event = eventqueue.get(block=False) print(event) # evaluate the event, check if checkbox-conditions match shelf_index = event["shelf"] if day[event["day_of_week"]].get()== 1 and \ hour[event["hour"]].get()== 1 and \ schedule_shelf[shelf_index].get()== 1 and \ activation_shelf[shelf_index].get()== 1: # call the button callback toggle_water_shelf(activation_pins[shelf_index], button_shelf[shelf_index], activation_labels[shelf_index]) except queue.Empty: break win.after(500,tk_callback ) win.after(500,tk_callback )win.mainloop()
I am new to all this coding, but I am good in designing GUI functionality in terms of what I want the GUI to perform for the project.
So if I want the scheduler to simulate button press for the watering shelves at set days and times, do you have any idea on how I could incorporate this to my existing code?
ChatGPT was very good at creating codes for my project from a precise descriptive text, but I am stuck with the scheduler not working...
Any help would be appreciated.
Cheers,
Statistics: Posted by papagino — Mon Mar 24, 2025 7:02 pm