Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5acf461cc6 | |||
| 36e90ce1fd | |||
| b62e50a354 | |||
| 9fd337f670 | |||
| 5e454264a3 | |||
| a29b230482 | |||
| 314b1c3ba7 | |||
| 3c4212bd03 | |||
| 426d7bbcaf | |||
| 4aff839f36 | |||
| 5f9db6397d | |||
| 4f94fc9669 | |||
| 3574700386 | |||
| 5764f28984 | |||
| 592453c1ff | |||
| 7352491d95 | |||
| afcd970b50 | |||
| b317923438 | |||
| e74d4b6d17 | |||
| 4e9d746332 | |||
| 016a063a66 | |||
| 4ed400abb6 | |||
| cf55fcf610 | |||
| c33ffcd6a8 | |||
| 5a97b27a77 | |||
| 2c65f30102 | |||
| de4a06cc3a | |||
| bb9383d896 | |||
| 365f2b3553 | |||
| bcbd3ab32a | |||
| 46fca79ffa | |||
| 3a231c5333 | |||
| d5917b285d | |||
| 452e31c278 | |||
| 8e8a5e80b6 | |||
| 6c715fa5ef | |||
| 128edc1ce9 | |||
| 56a3da70f7 | |||
| 2f15b7473e | |||
| 7f08b04859 | |||
| 2b5e8b149f | |||
| 9e208f3f7e | |||
| 22ad2e2c9d | |||
| 819d3f074e | |||
| 861e5dc33a | |||
| de0fe14e2d | |||
| fc0a6f9b90 | |||
| 86d35fba6b | |||
| 168754137a | |||
| 9e571f253f | |||
| bfb47d9d5e | |||
| 3b342a16c7 | |||
| 01daa88707 | |||
| dfb9b1948e | |||
| 5e10ff0cb2 | |||
| 3716b685a0 | |||
| a2ae52f294 | |||
| b864e731b1 | |||
| cbd5d695f9 | |||
| f8f047c84d |
BIN
biobizz/Acti Vera.jpg
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
biobizz/Alg A Mic.jpg
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
biobizz/All Mix.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
biobizz/Bio Bloom.jpg
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
biobizz/Bio Grow.jpg
Normal file
|
After Width: | Height: | Size: 66 KiB |
BIN
biobizz/Bio Heaven.jpg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
biobizz/Fish Mix.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
biobizz/Light Mix.jpg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
biobizz/PH+.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
biobizz/Root Juice.jpg
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
biobizz/Top Max.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
biobizz/calmag.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
biobizz/coco mix.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
biobizz/ph-.jpg
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
@@ -6,12 +6,15 @@ from mysql.connector import errorcode
|
||||
PROTOKOLL_TABLE_NAME = 'pflanzenprotokoll'
|
||||
PLANUNG_TABLE_NAME = 'pflanzenplanung'
|
||||
|
||||
def get_db_connection(config, with_db=False):
|
||||
"""Versucht, eine Verbindung zur Datenbank herzustellen."""
|
||||
def get_db_connection(config, with_db=True):
|
||||
"""
|
||||
Versucht, eine Verbindung zur Datenbank herzustellen.
|
||||
Standardmäßig wird versucht, die in der Config angegebene DB direkt zu nutzen.
|
||||
"""
|
||||
port = config.get('port', 3306)
|
||||
|
||||
db_args = {}
|
||||
if with_db:
|
||||
if with_db and 'database' in config:
|
||||
db_args['database'] = config['database']
|
||||
|
||||
try:
|
||||
@@ -41,7 +44,7 @@ def setup_database_and_table(cursor, db_name):
|
||||
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {db_name} DEFAULT CHARACTER SET 'utf8'")
|
||||
cursor.execute(f"USE {db_name}")
|
||||
except mysql.connector.Error as err:
|
||||
return False, f"Fehler beim Erstellen/Auswählen der Datenbank: {err}"
|
||||
return False, f"Fehler beim Erstellen oder Auswählen der Datenbank: {err}"
|
||||
|
||||
# Protokoll-Tabelle (Ist-Werte)
|
||||
PROTOKOLL_DESCRIPTION = f"""
|
||||
@@ -54,6 +57,8 @@ def setup_database_and_table(cursor, db_name):
|
||||
root_juice_ml_l FLOAT,
|
||||
calmag_ml_l FLOAT,
|
||||
bio_grow_ml_l FLOAT,
|
||||
fish_mix_ml_l FLOAT,
|
||||
bio_heaven_ml_l FLOAT,
|
||||
acti_alc_ml_l FLOAT,
|
||||
bio_bloom_ml_l FLOAT,
|
||||
top_max_ml_l FLOAT,
|
||||
@@ -73,6 +78,8 @@ def setup_database_and_table(cursor, db_name):
|
||||
root_juice_ml_l FLOAT,
|
||||
calmag_ml_l FLOAT,
|
||||
bio_grow_ml_l FLOAT,
|
||||
fish_mix_ml_l FLOAT,
|
||||
bio_heaven_ml_l FLOAT,
|
||||
acti_alc_ml_l FLOAT,
|
||||
bio_bloom_ml_l FLOAT,
|
||||
top_max_ml_l FLOAT,
|
||||
@@ -86,56 +93,65 @@ def setup_database_and_table(cursor, db_name):
|
||||
cursor.execute(PROTOKOLL_DESCRIPTION)
|
||||
cursor.execute(PLANUNG_DESCRIPTION)
|
||||
|
||||
# Sicherstellen, dass die Spalte ec_wert existiert (für Updates bestehender Tabellen)
|
||||
# Spalten nachträglich hinzufügen, falls sie fehlen (Migration)
|
||||
for table in [PROTOKOLL_TABLE_NAME, PLANUNG_TABLE_NAME]:
|
||||
# Fish-Mix
|
||||
try:
|
||||
cursor.execute(f"ALTER TABLE {table} ADD COLUMN fish_mix_ml_l FLOAT AFTER bio_grow_ml_l")
|
||||
except: pass
|
||||
# Bio-Heaven
|
||||
try:
|
||||
cursor.execute(f"ALTER TABLE {table} ADD COLUMN bio_heaven_ml_l FLOAT AFTER fish_mix_ml_l")
|
||||
except: pass
|
||||
# EC-Wert
|
||||
try:
|
||||
cursor.execute(f"ALTER TABLE {table} ADD COLUMN ec_wert FLOAT AFTER ph_wert_ziel")
|
||||
except mysql.connector.Error as err:
|
||||
if err.errno != 1060: # 1060 = Spalte existiert bereits, das ist okay
|
||||
print(f"Hinweis bei Alter Table {table}: {err.msg}")
|
||||
|
||||
return True, "Datenbankstruktur erfolgreich eingerichtet."
|
||||
except: pass
|
||||
|
||||
return True, "Datenbankstruktur erfolgreich eingerichtet oder aktualisiert."
|
||||
except mysql.connector.Error as err:
|
||||
return False, f"Fehler beim Erstellen der Tabellen: {err.msg}"
|
||||
|
||||
|
||||
def insert_pflanzen_data(cnx, datensatz):
|
||||
"""Fügt einen neuen IST-Datensatz (Protokoll) in die Tabelle ein und committet."""
|
||||
"""Fügt einen neuen IST-Datensatz (Protokoll) in die Tabelle ein."""
|
||||
cursor = cnx.cursor()
|
||||
|
||||
add_log = (f"INSERT INTO {PROTOKOLL_TABLE_NAME} "
|
||||
"(pflanzen_name, woche, phase, lichtzyklus_h, root_juice_ml_l, "
|
||||
"calmag_ml_l, bio_grow_ml_l, acti_alc_ml_l, bio_bloom_ml_l, "
|
||||
"top_max_ml_l, ph_wert_ziel, ec_wert, erstellungsdatum) "
|
||||
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)")
|
||||
"calmag_ml_l, bio_grow_ml_l, fish_mix_ml_l, bio_heaven_ml_l, acti_alc_ml_l, "
|
||||
"bio_bloom_ml_l, top_max_ml_l, ph_wert_ziel, ec_wert, erstellungsdatum) "
|
||||
"VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)")
|
||||
|
||||
try:
|
||||
cursor.execute(add_log, datensatz)
|
||||
last_id = cursor.lastrowid
|
||||
cnx.commit()
|
||||
cursor.close()
|
||||
return True, f"Datensatz erfolgreich eingefügt. (ID: {last_id})"
|
||||
return True, f"✅ Datensatz erfolgreich eingefügt. (ID: {last_id})"
|
||||
except mysql.connector.Error as err:
|
||||
cursor.close()
|
||||
return False, f"Fehler beim Einfügen des Datensatzes: {err.msg}"
|
||||
return False, f"❌ Fehler beim Einfügen des Datensatzes: {err.msg}"
|
||||
|
||||
|
||||
def save_pflanzen_plan(cnx, planungsdatensatz):
|
||||
"""Speichert oder aktualisiert einen SOLL-Datensatz (Planung) in der Tabelle."""
|
||||
"""Speichert oder aktualisiert einen SOLL-Datensatz in der Planungstabelle."""
|
||||
cursor = cnx.cursor()
|
||||
|
||||
save_plan = f"""
|
||||
INSERT INTO {PLANUNG_TABLE_NAME}
|
||||
(pflanzen_name, woche, phase, lichtzyklus_h, root_juice_ml_l,
|
||||
calmag_ml_l, bio_grow_ml_l, acti_alc_ml_l, bio_bloom_ml_l,
|
||||
top_max_ml_l, ph_wert_ziel, ec_wert)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
calmag_ml_l, bio_grow_ml_l, fish_mix_ml_l, bio_heaven_ml_l, acti_alc_ml_l,
|
||||
bio_bloom_ml_l, top_max_ml_l, ph_wert_ziel, ec_wert)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
phase = VALUES(phase),
|
||||
lichtzyklus_h = VALUES(lichtzyklus_h),
|
||||
root_juice_ml_l = VALUES(root_juice_ml_l),
|
||||
calmag_ml_l = VALUES(calmag_ml_l),
|
||||
bio_grow_ml_l = VALUES(bio_grow_ml_l),
|
||||
fish_mix_ml_l = VALUES(fish_mix_ml_l),
|
||||
bio_heaven_ml_l = VALUES(bio_heaven_ml_l),
|
||||
acti_alc_ml_l = VALUES(acti_alc_ml_l),
|
||||
bio_bloom_ml_l = VALUES(bio_bloom_ml_l),
|
||||
top_max_ml_l = VALUES(top_max_ml_l),
|
||||
@@ -147,20 +163,19 @@ def save_pflanzen_plan(cnx, planungsdatensatz):
|
||||
cursor.execute(save_plan, planungsdatensatz)
|
||||
cnx.commit()
|
||||
cursor.close()
|
||||
return True, "Planung erfolgreich gespeichert/aktualisiert."
|
||||
return True, "✅ Planung erfolgreich gespeichert/aktualisiert."
|
||||
except mysql.connector.Error as err:
|
||||
cursor.close()
|
||||
return False, f"Fehler beim Speichern der Planung: {err.msg}"
|
||||
return False, f"❌ Fehler beim Speichern der Planung: {err.msg}"
|
||||
|
||||
|
||||
def get_pflanzen_plan(config, plant_name, week):
|
||||
"""Ruft den Plan für eine spezifische Pflanze und Woche ab."""
|
||||
"""Holt einen spezifischen Plan (Soll-Werte) aus der DB."""
|
||||
cnx, result = get_db_connection(config, with_db=True)
|
||||
if cnx is None:
|
||||
return None, None
|
||||
|
||||
|
||||
cursor = cnx.cursor()
|
||||
|
||||
try:
|
||||
query = f"SELECT * FROM {PLANUNG_TABLE_NAME} WHERE pflanzen_name = %s AND woche = %s"
|
||||
cursor.execute(query, (plant_name, week))
|
||||
@@ -171,21 +186,19 @@ def get_pflanzen_plan(config, plant_name, week):
|
||||
cursor.close()
|
||||
cnx.close()
|
||||
return plan, column_names
|
||||
|
||||
except mysql.connector.Error:
|
||||
except:
|
||||
cursor.close()
|
||||
cnx.close()
|
||||
return None, None
|
||||
|
||||
|
||||
def fetch_all_data(config):
|
||||
"""Holt alle Protokolleinträge aus der Datenbank."""
|
||||
"""Holt alle Datensätze aus dem Protokoll für die Anzeige."""
|
||||
cnx, result = get_db_connection(config, with_db=True)
|
||||
if cnx is None:
|
||||
return None, result
|
||||
|
||||
|
||||
cursor = cnx.cursor()
|
||||
|
||||
try:
|
||||
cursor.execute(f"SELECT * FROM {PROTOKOLL_TABLE_NAME} ORDER BY erstellungsdatum DESC")
|
||||
data = cursor.fetchall()
|
||||
@@ -193,42 +206,36 @@ def fetch_all_data(config):
|
||||
cursor.close()
|
||||
cnx.close()
|
||||
return data, column_names
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
cursor.close()
|
||||
cnx.close()
|
||||
if err.errno == errorcode.ER_NO_SUCH_TABLE:
|
||||
return [], f"⚠️ Tabelle '{PROTOKOLL_TABLE_NAME}' existiert nicht. Speichern Sie zuerst einen Datensatz."
|
||||
elif err.errno == errorcode.ER_BAD_DB_ERROR:
|
||||
return [], f"⚠️ Datenbank '{config['database']}' existiert nicht."
|
||||
return None, f"Fehler beim Abrufen der Daten: {err.msg}"
|
||||
return None, f"❌ Fehler beim Abrufen der Daten: {err.msg}"
|
||||
|
||||
|
||||
def delete_data_by_id(config, record_id):
|
||||
"""Löscht einen Datensatz anhand seiner ID."""
|
||||
"""Löscht einen spezifischen Datensatz anhand der ID."""
|
||||
cnx, result = get_db_connection(config, with_db=True)
|
||||
if cnx is None:
|
||||
return False, result
|
||||
|
||||
|
||||
cursor = cnx.cursor()
|
||||
|
||||
try:
|
||||
delete_query = f"DELETE FROM {PROTOKOLL_TABLE_NAME} WHERE id = %s"
|
||||
cursor.execute(delete_query, (record_id,))
|
||||
query = f"DELETE FROM {PROTOKOLL_TABLE_NAME} WHERE id = %s"
|
||||
cursor.execute(query, (record_id,))
|
||||
cnx.commit()
|
||||
rows_affected = cursor.rowcount
|
||||
cursor.close()
|
||||
cnx.close()
|
||||
|
||||
if rows_affected > 0:
|
||||
return True, f"Datensatz (ID: {record_id}) erfolgreich gelöscht."
|
||||
return True, f"✅ Datensatz (ID: {record_id}) erfolgreich gelöscht."
|
||||
else:
|
||||
return False, f"Datensatz mit ID {record_id} nicht gefunden."
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
cursor.close()
|
||||
cnx.close()
|
||||
return False, f"Fehler beim Löschen des Datensatzes: {err.msg}"
|
||||
return False, f"❌ Fehler beim Löschen des Datensatzes: {err.msg}"
|
||||
|
||||
|
||||
def test_db_connection(config):
|
||||
@@ -255,6 +262,4 @@ def test_db_connection(config):
|
||||
elif err.errno == errorcode.ER_BAD_DB_ERROR:
|
||||
return False, f"⚠️ Datenbank '{config['database']}' existiert nicht. Wird beim Speichern erstellt."
|
||||
else:
|
||||
return False, f"❌ Unbekannter Verbindungsfehler: {err.msg}"
|
||||
except Exception as e:
|
||||
return False, f"❌ Allgemeiner Fehler: {e}"
|
||||
return False, f"❌ Fehler: {err.msg}"
|
||||
@@ -2,7 +2,7 @@
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
:: --- KONFIGURATION ---
|
||||
set "REPO_URL="http://diggerwf.cloud:8281/diggerwf/Brokkoli-Giess-Plannung-Helfer.git"
|
||||
set "REPO_URL="https://git.diggerwf.cloud/diggerwf/Brokkoli-Giess-Plannung-Helfer.git"
|
||||
set "BRANCH=main"
|
||||
set "START_FILE=start4.bat"
|
||||
:: ---------------------
|
||||
|
||||
1344
pflanzen_gui.py
207
start_app.py
@@ -1,87 +1,122 @@
|
||||
import sys
|
||||
import subprocess
|
||||
import tkinter as tk
|
||||
from tkinter import messagebox
|
||||
import os
|
||||
|
||||
# Konfiguration der benötigten Bibliotheken
|
||||
# Format: (Modulname für import, Name für pip, Kurzbeschreibung)
|
||||
REQUIRED_PACKAGES = [
|
||||
("PIL", "Pillow", "fuer die Bildanzeige (Logo)"),
|
||||
("mysql.connector", "mysql-connector-python", "fuer die Datenbankverbindung (MySQL)")
|
||||
]
|
||||
|
||||
def ensure_pip():
|
||||
"""Stellt sicher, dass pip aktuell ist, bevor Pakete installiert werden."""
|
||||
try:
|
||||
print("🔍 Bereite Paket-Manager (pip) vor...")
|
||||
# Aktualisiert pip im Hintergrund (ohne Bestätigung)
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", "pip"],
|
||||
stdout=subprocess.DEVNULL)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"⚠️ Warnung beim pip-Update: {e}")
|
||||
return True # Wir versuchen es trotzdem weiter
|
||||
|
||||
def check_and_install_packages():
|
||||
"""Prüft Abhängigkeiten und installiert sie bei Bedarf grafisch."""
|
||||
# Unsichtbares Tkinter-Hauptfenster für Dialoge
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
|
||||
all_ready = True
|
||||
|
||||
for import_name, pip_name, description in REQUIRED_PACKAGES:
|
||||
try:
|
||||
# Versuch, das Modul zu laden
|
||||
__import__(import_name)
|
||||
print(f"✅ Modul vorhanden: {import_name}")
|
||||
except ImportError:
|
||||
print(f"❌ Modul fehlt: {import_name}")
|
||||
|
||||
# Grafische Abfrage beim Nutzer
|
||||
frage = (f"Die Bibliothek '{pip_name}' ({description}) fehlt.\n\n"
|
||||
f"Soll sie jetzt automatisch installiert werden?")
|
||||
|
||||
if messagebox.askyesno("Abhängigkeit installieren", frage):
|
||||
try:
|
||||
# Pip vorbereiten (nur wenn wirklich installiert werden muss)
|
||||
ensure_pip()
|
||||
|
||||
print(f"📥 Installiere {pip_name}...")
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", pip_name])
|
||||
print(f"✅ {pip_name} erfolgreich installiert.")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Fehler", f"Installation von {pip_name} fehlgeschlagen:\n{e}")
|
||||
all_ready = False
|
||||
else:
|
||||
messagebox.showwarning("Warnung", f"Ohne {pip_name} wird die App wahrscheinlich abstuerzen.")
|
||||
all_ready = False
|
||||
|
||||
root.destroy()
|
||||
return all_ready
|
||||
|
||||
def start_main_app():
|
||||
"""Startet die eigentliche GUI-Datei."""
|
||||
try:
|
||||
print("🚀 Lade Pflanzenprotokoll-Oberflaeche...")
|
||||
# Hier wird deine eigentliche Datei importiert und gestartet
|
||||
import pflanzen_gui
|
||||
app = pflanzen_gui.PflanzenApp()
|
||||
app.mainloop()
|
||||
except Exception as e:
|
||||
error_msg = f"Kritischer Fehler beim Starten von pflanzen_gui.py:\n{e}"
|
||||
print(error_msg)
|
||||
# Kurzes Notfall-Fenster für den Fehler
|
||||
temp_root = tk.Tk()
|
||||
temp_root.withdraw()
|
||||
messagebox.showerror("Programmfehler", error_msg)
|
||||
temp_root.destroy()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Schritt 1: Pakete prüfen
|
||||
if check_and_install_packages():
|
||||
# Schritt 2: Wenn alles okay ist, Haupt-App starten
|
||||
start_main_app()
|
||||
else:
|
||||
import sys
|
||||
import subprocess
|
||||
import tkinter as tk
|
||||
from tkinter import messagebox
|
||||
import os
|
||||
|
||||
# Konfiguration der benötigten Bibliotheken
|
||||
# Format: (Modulname für import, Name für pip, Kurzbeschreibung)
|
||||
REQUIRED_PACKAGES = [
|
||||
("PIL", "Pillow", "fuer die Bildanzeige (Logo)"),
|
||||
("mysql.connector", "mysql-connector-python", "fuer die Datenbankverbindung (MySQL)"),
|
||||
("pandas", "pandas", "fuer die Datenverarbeitung und Tabellen"),
|
||||
("rich", "rich", "fuer formatierte Konsolenausgaben")
|
||||
]
|
||||
|
||||
def ensure_pip():
|
||||
"""Stellt sicher, dass pip aktuell ist, bevor Pakete installiert werden."""
|
||||
try:
|
||||
print("🔍 Bereite Paket-Manager (pip) vor...")
|
||||
# Aktualisiert pip im Hintergrund (ohne Bestätigung)
|
||||
# Unter Linux wird hier --break-system-packages genutzt, um die PEP 668 Sperre zu umgehen
|
||||
cmd = [sys.executable, "-m", "pip", "install", "--upgrade", "pip"]
|
||||
if sys.platform.startswith('linux'):
|
||||
cmd.append("--break-system-packages")
|
||||
|
||||
subprocess.check_call(cmd, stdout=subprocess.DEVNULL)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"⚠️ Warnung beim pip-Update: {e}")
|
||||
# Falls pip nicht gefunden wird, versuchen wir es unter Linux mit ensurepip
|
||||
if sys.platform.startswith('linux'):
|
||||
try:
|
||||
print("🔄 Versuche pip via System-Paketmanager zu finden...")
|
||||
subprocess.check_call([sys.executable, "-m", "ensurepip", "--default-pip"], stdout=subprocess.DEVNULL)
|
||||
except:
|
||||
pass
|
||||
return True # Wir versuchen es trotzdem weiter
|
||||
|
||||
def check_and_install_packages():
|
||||
"""Prüft Abhängigkeiten einzeln und installiert sie bei Bedarf grafisch."""
|
||||
# Unsichtbares Tkinter-Hauptfenster für Dialoge
|
||||
root = tk.Tk()
|
||||
root.withdraw()
|
||||
|
||||
all_ready = True
|
||||
|
||||
for import_name, pip_name, description in REQUIRED_PACKAGES:
|
||||
try:
|
||||
# Gründliche Einzelprüfung: Versucht das Modul wirklich zu laden
|
||||
if import_name == "pandas":
|
||||
import pandas as pd
|
||||
# Kleiner Funktionstest für Pandas
|
||||
pd.DataFrame()
|
||||
elif import_name == "PIL":
|
||||
from PIL import Image, ImageTk
|
||||
elif import_name == "rich":
|
||||
import rich
|
||||
from rich.console import Console
|
||||
_ = Console()
|
||||
else:
|
||||
__import__(import_name)
|
||||
|
||||
print(f"✅ Modul vorhanden und funktionsfaehig: {import_name}")
|
||||
except (ImportError, ModuleNotFoundError, Exception):
|
||||
print(f"❌ Modul fehlt oder ist defekt: {import_name}")
|
||||
|
||||
# Grafische Abfrage beim Nutzer
|
||||
is_linux = sys.platform.startswith('linux')
|
||||
zusatz_info = "\n(Nutzt --break-system-packages unter Linux)" if is_linux else ""
|
||||
|
||||
frage = (f"Die Bibliothek '{pip_name}' ({description}) fehlt.\n\n"
|
||||
f"Soll sie jetzt automatisch installiert werden?{zusatz_info}")
|
||||
|
||||
if messagebox.askyesno("Abhängigkeit installieren", frage):
|
||||
try:
|
||||
# Pip vorbereiten
|
||||
ensure_pip()
|
||||
|
||||
print(f"📥 Installiere {pip_name}...")
|
||||
# Installation über den aktuellen Python-Interpreter
|
||||
install_cmd = [sys.executable, "-m", "pip", "install", pip_name]
|
||||
|
||||
# Fix für das 'externally-managed-environment' Problem unter Linux
|
||||
if is_linux:
|
||||
install_cmd.append("--break-system-packages")
|
||||
|
||||
subprocess.check_call(install_cmd)
|
||||
print(f"✅ {pip_name} erfolgreich installiert.")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Fehler", f"Installation von {pip_name} fehlgeschlagen:\n{e}")
|
||||
all_ready = False
|
||||
else:
|
||||
messagebox.showwarning("Warnung", f"Ohne {pip_name} wird die App wahrscheinlich abstuerzen.")
|
||||
all_ready = False
|
||||
|
||||
root.destroy()
|
||||
return all_ready
|
||||
|
||||
def start_main_app():
|
||||
"""Startet die eigentliche GUI-Datei."""
|
||||
try:
|
||||
print("🚀 Lade Pflanzenprotokoll-Oberflaeche...")
|
||||
# Hier wird deine eigentliche Datei importiert und gestartet
|
||||
import pflanzen_gui
|
||||
app = pflanzen_gui.PflanzenApp()
|
||||
app.mainloop()
|
||||
except Exception as e:
|
||||
error_msg = f"Kritischer Fehler beim Starten von pflanzen_gui.py:\n{e}"
|
||||
print(error_msg)
|
||||
# Kurzes Notfall-Fenster für den Fehler
|
||||
temp_root = tk.Tk()
|
||||
temp_root.withdraw()
|
||||
messagebox.showerror("Programmfehler", error_msg)
|
||||
temp_root.destroy()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Schritt 1: Jedes Paket einzeln prüfen
|
||||
if check_and_install_packages():
|
||||
# Schritt 2: Wenn alles okay ist, Haupt-App starten
|
||||
start_main_app()
|
||||
else:
|
||||
print("❌ Start abgebrochen, da Komponenten fehlen.")
|
||||
98
update.bat
@@ -1,99 +1,59 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
:: 🎨 KONFIGURATION
|
||||
set "REPO_URL=http://diggerwf.cloud:8281/diggerwf/Brokkoli-Giess-Plannung-Helfer.git"
|
||||
set "REPO_URL=https://git.diggerwf.cloud/diggerwf/Brokkoli-Giess-Plannung-Helfer.git"
|
||||
set "BRANCH=main"
|
||||
set "ORIGIN=origin"
|
||||
set "REPO_DIR=%~dp0"
|
||||
set "START_FILE=start4.bat"
|
||||
set "SELF_NAME=update.bat"
|
||||
set "TEMP_NAME=temp_updater.bat"
|
||||
|
||||
:: 🛡️ AUSNAHMEN-KONFIGURATION
|
||||
:: Diese Dateien werden von Git beim Aufräumen (clean) ignoriert
|
||||
set SKIP_PARAMS=-e "config.json" -e "settings.txt" -e "db_config.ini" -e "logs/" -e "saves/" -e "__pycache__"
|
||||
|
||||
set "SKIP_PARAMS=-e config.json -e settings.txt -e db_config.ini -e logs/ -e saves/ -e __pycache__"
|
||||
cd /d "%REPO_DIR%"
|
||||
|
||||
:: 🔄 SCHRITT 0: BIN ICH DIE KOPIE (DER HELFER)?
|
||||
:: Dieser Teil wird nur ausgeführt, wenn die temp_updater.bat aktiv ist
|
||||
if "%~nx0"=="%TEMP_NAME%" (
|
||||
echo 🛠️ Update-Modus aktiv...
|
||||
echo Update-Modus aktiv...
|
||||
timeout /t 2 >nul
|
||||
|
||||
:: Hier wird das Original auf der Festplatte überschrieben
|
||||
git fetch origin %BRANCH% --quiet
|
||||
git reset --hard origin/%BRANCH% --quiet
|
||||
git fetch %ORIGIN% %BRANCH% --quiet
|
||||
git reset --hard %ORIGIN%/%BRANCH% --quiet
|
||||
git clean -fd %SKIP_PARAMS% >nul
|
||||
|
||||
echo ✅ Dateien wurden auf der Festplatte aktualisiert.
|
||||
echo 🚀 Starte das neue Hauptskript...
|
||||
|
||||
:: Wir starten das Original-Skript neu und beenden die Kopie
|
||||
call "%SELF_NAME%"
|
||||
exit
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
:: 🗑️ SCHRITT 1: AUFRÄUMEN
|
||||
:: Wenn das Original startet, löscht es eine eventuell vorhandene Kopie
|
||||
if exist "%TEMP_NAME%" del /f /q "%TEMP_NAME%"
|
||||
|
||||
echo 🔍 Prüfe auf Updates für: !REPO_URL!
|
||||
|
||||
:: 🛠️ 2. GIT CHECK
|
||||
echo Pruefe auf Updates...
|
||||
git --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo ❌ Git nicht gefunden! Installiere...
|
||||
winget install --id Git.Git -e --source winget --accept-package-agreements --accept-source-agreements
|
||||
echo Git nicht gefunden!
|
||||
pause
|
||||
exit /b
|
||||
)
|
||||
|
||||
:: 🔄 3. UPDATE LOGIK
|
||||
if exist ".git\" (
|
||||
git remote set-url origin "!REPO_URL!"
|
||||
git fetch origin %BRANCH% --quiet
|
||||
|
||||
git remote set-url %ORIGIN% "%REPO_URL%"
|
||||
git fetch %ORIGIN% %BRANCH% || (echo Fehler: Server nicht erreichbar & pause & exit /b)
|
||||
for /f "tokens=*" %%a in ('git rev-parse HEAD') do set "LOCAL_HASH=%%a"
|
||||
for /f "tokens=1" %%a in ('git ls-remote origin %BRANCH%') do set "REMOTE_HASH=%%a"
|
||||
|
||||
echo 🏠 Lokal: !LOCAL_HASH:~0,7!
|
||||
echo 🌐 Online: !REMOTE_HASH:~0,7!
|
||||
|
||||
for /f "tokens=1" %%a in ('git ls-remote %ORIGIN% %BRANCH%') do set "REMOTE_HASH=%%a"
|
||||
echo Lokal: !LOCAL_HASH:~0,7!
|
||||
echo Online: !REMOTE_HASH:~0,7!
|
||||
if "!LOCAL_HASH!" neq "!REMOTE_HASH!" (
|
||||
echo 🆕 Update verfügbar!
|
||||
echo 📦 Erstelle temporäre Kopie zur Aktualisierung...
|
||||
|
||||
:: Wir kopieren uns selbst, damit die Kopie das Original überschreiben kann
|
||||
echo Update verfuegbar...
|
||||
copy /y "%SELF_NAME%" "%TEMP_NAME%" >nul
|
||||
|
||||
:: Wir starten die Kopie und BEENDEN dieses Skript sofort (Wichtig!)
|
||||
call "%TEMP_NAME%"
|
||||
exit
|
||||
exit /b
|
||||
) else (
|
||||
echo ✅ Alles aktuell!
|
||||
echo Alles aktuell.
|
||||
)
|
||||
) else (
|
||||
echo 🏗️ Ersteinrichtung läuft... 🔧
|
||||
echo Ersteinrichtung...
|
||||
git init --quiet
|
||||
git remote add origin "!REPO_URL!" 2>nul
|
||||
git fetch --all --quiet
|
||||
git reset --hard origin/%BRANCH% --quiet
|
||||
git clean -fd %SKIP_PARAMS% >nul
|
||||
echo 🔗 Repository erfolgreich eingerichtet!
|
||||
git remote add %ORIGIN% "%REPO_URL%"
|
||||
git fetch --all
|
||||
git reset --hard %ORIGIN%/%BRANCH%
|
||||
git clean -fd %SKIP_PARAMS%
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ✨ System ist bereit.
|
||||
|
||||
:: 🚀 4. START DES HAUPTPROGRAMMS
|
||||
if exist "!START_FILE!" (
|
||||
echo 🚀 Starte !START_FILE! via CALL...
|
||||
:: Hier wird CALL genutzt, damit das Fenster für dein Programm offen bleibt
|
||||
call "!START_FILE!"
|
||||
if exist "%START_FILE%" (
|
||||
call "%START_FILE%"
|
||||
) else (
|
||||
echo ⚠️ !START_FILE! wurde nicht gefunden.
|
||||
echo Fehler: %START_FILE% nicht gefunden!
|
||||
pause
|
||||
)
|
||||
exit
|
||||
::test
|
||||
|
||||
)
|
||||
@@ -4,7 +4,7 @@
|
||||
ENDSTART="start.sh"
|
||||
|
||||
# GitHub-Repository-URL und Branch definieren
|
||||
REPO_URL="http://diggerwf.cloud:8281/diggerwf/Brokkoli-Giess-Plannung-Helfer.git"
|
||||
REPO_URL="https://git.diggerwf.cloud/diggerwf/Brokkoli-Giess-Plannung-Helfer.git"
|
||||
BRANCH="main"
|
||||
|
||||
# Pfad zum Repository (aktueller Ordner)
|
||||
|
||||