From 8df9fa61f36c9fd68315050121fef6fbc8472bcc Mon Sep 17 00:00:00 2001 From: giusber2005 <156716475+giusber2005@users.noreply.github.com> Date: Fri, 1 Aug 2025 23:55:50 +0200 Subject: [PATCH] first round of development --- .DS_Store | Bin 0 -> 6148 bytes .../main_dashboard.cpython-313.pyc | Bin 0 -> 22946 bytes PlantDashboard/main_dashboard.py | 223 +++++++----------- PlantDashboard/requirements.txt | 2 + PlantDashboard/{ => utils}/demo_launcher.py | 2 +- PlantDashboard/{ => utils}/graphics_demo.py | 0 .../{ => utils}/install_requirements.py | 0 path.txt | 6 - 8 files changed, 82 insertions(+), 151 deletions(-) create mode 100644 .DS_Store create mode 100644 PlantDashboard/__pycache__/main_dashboard.cpython-313.pyc rename PlantDashboard/{ => utils}/demo_launcher.py (96%) rename PlantDashboard/{ => utils}/graphics_demo.py (100%) rename PlantDashboard/{ => utils}/install_requirements.py (100%) diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4a50b4227e0608dbad2ca11fce82641463a3ee60 GIT binary patch literal 6148 zcmeHK%Wl&^6upxMVpD;#04W=!k-7~b2^56bq-g?FDlMuJEC2;N4%DjaiDHK!MUlLQ zf8ZC`@+JHWD>(Bg%A+71C#C*)HfOdq^s66l3flj`toM7Q9NX+&ch;wO-M z1fGXch7{7f#ZlPJrBNKT(*2%0EB0fl{WW@qC-E_dj5@#+GYT-Oj~RrEV-?=7!wn|s zFo=~J--2NrrCGiHofS5UmoAr_lC$Z&@s7pB%lvGdw*Ap7nR_lo9Gt~|@FE&adgbf8 zBFX$H8H^Mm3I}NN`el@aV$v4lBuo|8(-n^ExV>^^I&IXqtGs!?F{|?FgJ!+T@7}pL zo4L-7t=kWedMEK|B0k}HV2o*`s|L^DGlIYB^T8V>u}GvYvJaPzuzPl(<5OUbPL~x_ zyXec@E~-HF0W{CB_x8b(J4%*}pno4xq;^LGYiibLaYdM%;ry;d*4mm1nALYS*W}se zRspNP#aBRnA2?iM%V4fieL9e+D*&*FVr7Wsp9aa{23rPmji`Y!O$BNyGgl0z=_u!> zUCUsuQPYW;%Lg+fGjl^>YIO9^RdZr3jW)FkSOpdp*wERsJpa3YzW*qvj{pDw literal 0 HcmV?d00001 diff --git a/PlantDashboard/__pycache__/main_dashboard.cpython-313.pyc b/PlantDashboard/__pycache__/main_dashboard.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..287e6941f5b75d9a78dd225b0cab66110b3ae52b GIT binary patch literal 22946 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 YbmrNaWo`c7>X>hJt!gP<0qN&|0RZ*0fdBvi literal 0 HcmV?d00001 diff --git a/PlantDashboard/main_dashboard.py b/PlantDashboard/main_dashboard.py index be5fcf1..fca9b7d 100644 --- a/PlantDashboard/main_dashboard.py +++ b/PlantDashboard/main_dashboard.py @@ -1,17 +1,11 @@ import tkinter as tk from tkinter import ttk, filedialog, messagebox -import matplotlib.pyplot as plt -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg -import pandas as pd -import numpy as np from PIL import Image, ImageTk import json import os -from datetime import datetime, timedelta -import joblib +from datetime import datetime from plant_model import PlantGrowthModel from data_handler import DataHandler -from image_generator import ImageGenerator class PlantGrowthDashboard: def __init__(self, root): @@ -29,7 +23,6 @@ class PlantGrowthDashboard: # Initialize components self.plant_model = PlantGrowthModel() self.data_handler = DataHandler() - self.image_generator = ImageGenerator() # Variables - fixed plant type self.current_plant = "tomato" # Fixed plant type @@ -110,10 +103,9 @@ class PlantGrowthDashboard: ttk.Button(control_frame, text="šŸ“· Load Plant Image", command=self.load_baseline_image).grid(row=2, column=0, columnspan=2, pady=(0, 10), sticky=(tk.W, tk.E)) - # Environmental parameters ttk.Label(control_frame, text="Parameters:", - font=('Arial', 9, 'bold')).grid(row=3, column=0, columnspan=2, sticky=tk.W, pady=(0, 4)) - + font=('Arial', 9, 'bold')).grid(row=3, column=0, columnspan=2, sticky=tk.W, pady=(0, 4)) + param_labels = { 'temperature': 'šŸŒ”ļø Temp (°C)', 'humidity': 'šŸ’§ Humidity (%)', @@ -124,7 +116,19 @@ class PlantGrowthDashboard: 'water': 'šŸ’¦ Water (%)', 'co2': '🫧 CO2' } - + + # Define bounds for each parameter (min, max) + param_bounds = { + 'temperature': (10, 40), + 'humidity': (20, 90), + 'soil_acidity': (4.0, 9.0), + 'pressure': (950, 1100), + 'brightness': (100, 100000), + 'nutrients': (0, 100), + 'water': (10, 100), + 'co2': (300, 1000) + } + row = 4 for param, label in param_labels.items(): # Compact parameter layout @@ -133,21 +137,12 @@ class PlantGrowthDashboard: ttk.Label(param_frame, text=label, width=11, font=('Arial', 8)).pack(side=tk.LEFT) - # Scale ranges based on parameter type - if param == 'co2': - scale_max = 1000 - elif param == 'brightness': - scale_max = 100000 - elif param == 'pressure': - scale_max = 1100 - elif param == 'soil_acidity': - scale_max = 14 - else: - scale_max = 100 - - scale = ttk.Scale(param_frame, from_=0, to=scale_max, - variable=self.env_params[param], orient=tk.HORIZONTAL, - command=lambda x, p=param: self.on_param_change(p)) + # Get bounds for this parameter + scale_min, scale_max = param_bounds.get(param, (0, 100)) + + scale = ttk.Scale(param_frame, from_=scale_min, to=scale_max, + variable=self.env_params[param], orient=tk.HORIZONTAL, + command=lambda x, p=param: self.on_param_change(p)) scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(4, 4)) # Value label @@ -212,7 +207,7 @@ class PlantGrowthDashboard: info_frame.pack(fill=tk.X, pady=(8, 0)) self.plant_info_text = tk.Text(info_frame, height=8, width=35, wrap=tk.WORD, - font=('Arial', 8), bg='#f8f9fa') + font=('Arial', 8), bg="#000000") self.plant_info_text.pack(fill=tk.BOTH, expand=True) # Submit button @@ -283,10 +278,31 @@ class PlantGrowthDashboard: for param_name, default_value in self.default_params.items(): self.env_params[param_name].set(default_value) + self.update_parameter_label(param_name, default_value) + self.ambient_mode.set("controlled") self.update_prediction() - + + def update_parameter_label(self, param, value): + """Update the value label for a specific parameter""" + try: + # Get the value label for this parameter + value_label = getattr(self, f"{param}_value_label") + + # Format the value based on parameter type + if param == 'soil_acidity': + value_label.config(text=f"{value:.1f}") + elif param in ['brightness', 'pressure', 'co2']: + value_label.config(text=f"{value:.0f}") + else: + value_label.config(text=f"{value:.1f}") + except AttributeError: + # Handle case where label doesn't exist + print(f"Warning: No label found for parameter {param}") + def load_baseline_image(self): + self.results_text.delete(1.0, tk.END) + file_path = filedialog.askopenfilename( title="Select baseline plant image", filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp *.gif")] @@ -308,15 +324,27 @@ class PlantGrowthDashboard: 'timestamp': datetime.now().isoformat(), 'parameters': params, 'baseline_image_path': self.baseline_image_path, - 'plant_info': self.plant_info_text.get(1.0, tk.END), - 'results': self.results_text.get(1.0, tk.END) + 'plant_info': self.plant_info_text.get(1.0, tk.END) } - # Show confirmation dialog - messagebox.showinfo("Submission Successful", - "Plant information and photo have been submitted successfully!\n\n" - f"Submission ID: {datetime.now().strftime('%Y%m%d_%H%M%S')}") + #Remove plant_info_text + self.plant_info_text.delete(1.0, tk.END) + data_dir = "../data" + os.makedirs(data_dir, exist_ok=True) + current_date = datetime.now().strftime('%Y%m%d') + filename = f"{current_date}-{current_date}.txt" + filepath = os.path.join(data_dir, filename) + with open(filepath, 'w') as f: + json.dump(submission_data, f, indent=4) + + # Here call the bot pipeline to store results on files in plant_data + + # Here update the informations in the last box from plant_data/texts + + # Here update the informations in growth evolution from plant_data/images + + print(f"Submission data saved to: {filepath}") except Exception as e: messagebox.showerror("Submission Error", f"Error submitting data: {str(e)}") @@ -331,10 +359,7 @@ class PlantGrowthDashboard: prediction = self.plant_model.predict_growth(params) # Update initial plant display - self.update_initial_plant_display(params, prediction) - - # Generate plant evolution images - self.generate_plant_evolution(params, prediction) + self.update_initial_plant_display() # Update results text self.update_results_display(prediction) @@ -342,125 +367,35 @@ class PlantGrowthDashboard: except Exception as e: messagebox.showerror("Prediction Error", f"Error generating prediction: {str(e)}") - def update_initial_plant_display(self, params, prediction): + def update_initial_plant_display(self): """Update the initial plant state display""" try: + initial_image = None # Generate initial plant image (stage 0) - initial_image = self.image_generator.generate_plant_image( - self.current_plant, 0.5, prediction['health_score'], 0 - ) + try: + if self.baseline_image_path != None and os.path.exists(self.baseline_image_path): + initial_image = Image.open(self.baseline_image_path) + except Exception as e: + print(f"Error loading image from {self.baseline_image_path}: {e}") # Resize image to fit better in square layout - initial_image = initial_image.resize((280, 210), Image.Resampling.LANCZOS) - # Convert to PhotoImage and display - photo = ImageTk.PhotoImage(initial_image) - self.initial_plant_label.configure(image=photo, text="") - self.initial_plant_label.image = photo # Keep reference + if initial_image != None: + initial_image = initial_image.resize((280, 210), Image.Resampling.LANCZOS) - # Update plant information - self.update_plant_info(params, prediction) + # Convert to PhotoImage and display + photo = ImageTk.PhotoImage(initial_image) + self.initial_plant_label.configure(image=photo, text="") + self.initial_plant_label.image = photo # Keep reference except Exception as e: messagebox.showerror("Image Error", f"Could not generate initial plant image: {str(e)}") - - def update_plant_info(self, params, prediction): - """Update plant information display""" - self.plant_info_text.delete(1.0, tk.END) - - info_text = f"""🌱 PLANT STATUS -{'='*22} -Plant Type: Tomato -Health Score: {prediction['health_score']:.1f}% -Growth Rate: {prediction['growth_rate']:.2f} cm/day - -šŸŒ”ļø CONDITIONS: -Temperature: {params['temperature']:.1f}°C -Humidity: {params['humidity']:.1f}% -Soil pH: {params['soil_acidity']:.1f} -Light: {params['brightness']:.0f} lux -Water: {params['water']:.1f}% -Nutrients: {params['nutrients']:.1f}% - -šŸ“Š FORECAST: -Final Height: {prediction['final_height']:.1f} cm -Expected Yield: {prediction.get('yield', 'N/A')} -Optimal Conditions: {prediction['optimal_conditions']:.1f}% -""" - - self.plant_info_text.insert(1.0, info_text) - - def generate_plant_evolution(self, params, prediction): - """Generate and display plant evolution images""" - try: - # Generate plant evolution images - images = self.image_generator.generate_evolution( - self.current_plant, params, prediction, self.baseline_image_path - ) - - if images: - # Clear previous images - for widget in self.image_display_frame.winfo_children(): - widget.destroy() - - # Display evolution stages in a square grid - stages_per_row = 2 # Square layout - for i, image in enumerate(images): - row = i // stages_per_row - col = i % stages_per_row - - stage_frame = ttk.Frame(self.image_display_frame) - stage_frame.grid(row=row, column=col, padx=4, pady=4, sticky=(tk.W, tk.E)) - - # Stage label - ttk.Label(stage_frame, text=f"Stage {i+1}", - font=('Arial', 9, 'bold')).pack() - - # Resize image for compact display - resized_image = image.resize((180, 135), Image.Resampling.LANCZOS) - - # Convert PIL image to PhotoImage - photo = ImageTk.PhotoImage(resized_image) - image_label = tk.Label(stage_frame, image=photo) - image_label.image = photo # Keep a reference - image_label.pack() - - # Configure grid weights for even distribution - for col in range(stages_per_row): - self.image_display_frame.columnconfigure(col, weight=1) - - except Exception as e: - messagebox.showerror("Evolution Error", f"Could not generate evolution images: {str(e)}") - def update_results_display(self, prediction): self.results_text.delete(1.0, tk.END) - results = f"""🌱 GROWTH FORECAST -{'='*18} - -Final Height: {prediction['final_height']:.1f} cm -Growth Rate: {prediction['growth_rate']:.2f} cm/day -Health Score: {prediction['health_score']:.1f}/100 - -šŸ“… Growth Phases: -""" - - for phase in prediction.get('phases', []): - results += f"• {phase['name']}: Days {phase['start']}-{phase['end']}\n" - - results += f"\nāœ… Optimal Conditions: {prediction['optimal_conditions']:.1f}%" - results += f"\nšŸ… Expected Yield: {prediction.get('yield', 'N/A')}" - - # Add environmental summary - results += f"\n\nšŸŒ”ļø ENVIRONMENT SUMMARY:" - results += f"\nTemperature: {self.env_params['temperature'].get():.1f}°C" - results += f"\nHumidity: {self.env_params['humidity'].get():.1f}%" - results += f"\nSoil pH: {self.env_params['soil_acidity'].get():.1f}" - results += f"\nLight Level: {self.env_params['brightness'].get():.0f} lux" - results += f"\nWater Level: {self.env_params['water'].get():.1f}%" - results += f"\nNutrients: {self.env_params['nutrients'].get():.1f}%" - results += f"\nCO2 Level: {self.env_params['co2'].get():.0f} ppm" + #Here update the results display after submitting the photo and the message with the parameters and receveing the output + results = "" self.results_text.insert(1.0, results) diff --git a/PlantDashboard/requirements.txt b/PlantDashboard/requirements.txt index 8059b13..90880d9 100644 --- a/PlantDashboard/requirements.txt +++ b/PlantDashboard/requirements.txt @@ -28,6 +28,8 @@ colorlog>=6.6.0 psutil>=5.8.0 memory-profiler>=0.60.0 +tkcalendar + # Note: tkinter comes pre-installed with most Python distributions # If tkinter is not available, install it using your system package manager: # Ubuntu/Debian: sudo apt-get install python3-tk diff --git a/PlantDashboard/demo_launcher.py b/PlantDashboard/utils/demo_launcher.py similarity index 96% rename from PlantDashboard/demo_launcher.py rename to PlantDashboard/utils/demo_launcher.py index 00db47a..efd1869 100644 --- a/PlantDashboard/demo_launcher.py +++ b/PlantDashboard/utils/demo_launcher.py @@ -49,7 +49,7 @@ def main(): print("\nšŸš€ Starting graphics demo...") try: - from graphics_demo import PlantGrowthGraphicsDemo + from PlantDashboard.utils.graphics_demo import PlantGrowthGraphicsDemo import tkinter as tk root = tk.Tk() diff --git a/PlantDashboard/graphics_demo.py b/PlantDashboard/utils/graphics_demo.py similarity index 100% rename from PlantDashboard/graphics_demo.py rename to PlantDashboard/utils/graphics_demo.py diff --git a/PlantDashboard/install_requirements.py b/PlantDashboard/utils/install_requirements.py similarity index 100% rename from PlantDashboard/install_requirements.py rename to PlantDashboard/utils/install_requirements.py diff --git a/path.txt b/path.txt index 0803001..cb50234 100644 --- a/path.txt +++ b/path.txt @@ -4,7 +4,6 @@ ROADMAP -add the possibility to retrieve all the data when the user click the submit button -format the data in an usable format - -resolve numpy.float64 bug -differences between the three modes: Open mode: -the temp, humidity, light, water parameters are setted by the meteo api, the rest is setted by the user @@ -23,8 +22,6 @@ ROADMAP -The growth evolution will have as input the photo/s obtained by the model (the output will be in the text folder inside data/images folder, format "date1-date2-enum.jpg) - -make the plant information as a text field, remove all the connections with other functions - -set the value of light as Daily Light Integral (DLI) -forecast for a period of time: @@ -36,6 +33,3 @@ ROADMAP -final updates of README.md, hackathon page, forgejo, github page, small design adjustments. - -DURING DINNER - -update all on forgejo, hackathon page, forgejo \ No newline at end of file