drawdxf sammelt ALLE Atikelnummern (Kabel, Motoren, Sensoren), prüft lokale bezeichner.cfg, ob für alle artikelnummern ein bezeichner vorhanden. Falls kein bezeichner vorhanden wird bezeichner.cfg um Block [Missing] ergänzt, und SIVAS Datenabfrage dafür gestartet. Scahlter --local zur vermeidung der Abfrage verfügbar

This commit is contained in:
2025-06-23 11:55:23 +02:00
parent 8e653aca20
commit 2f982bf5f4
3 changed files with 138 additions and 144 deletions
+49 -62
View File
@@ -10,7 +10,7 @@ from openpyxl import Workbook
import math
from collections import defaultdict
import configparser
from updateconfignames import get_sivas_teilestamm, read_bezeichner_from_csv
import updateconfignames as uc
@dataclass
@@ -266,15 +266,36 @@ def parse_sensors_from_json(positions_json):
sensors[name] = sensor
return sensors
def export_excel(plines, out_path):
def export_excel(plines, sens2cable, out_path):
# Hier für Excel Export
print("creating excel file with cable information ..")
write_excel_from_json(plines, out_path)
write_excel_from_json(plines, sens2cable, out_path)
print("done")
def write_excel_from_json(plines:Polylines, outpath:str):
def get_all_artnrs(plines: Polylines, sens2cable: dict) -> set:
all_artnrs = set()
for pl in plines.kabel:
if pl.s_artinr:
all_artnrs.add(pl.s_artinr)
for cablelist in sens2cable.values():
for artnr in cablelist:
if isinstance(artnr, str) and artnr.isdigit():
all_artnrs.add(artnr)
return all_artnrs
def mark_missings(all_artnrs):
if "Sivasnummern" not in bezeichner_cfg:
bezeichner_cfg["Sivasnummern"] = {}
if "Missing" not in bezeichner_cfg:
bezeichner_cfg["Missing"] = {}
for artnr in all_artnrs:
if artnr not in bezeichner_cfg["Sivasnummern"]:
bezeichner_cfg["Missing"][artnr] = ""
def write_excel_from_json(plines:Polylines, sens2cable: dict, outpath:str):
wb = Workbook()
sens2cable = map_sensor_to_cable_cfg(plines)
# Dicts für Anzahl bzw kummulierte Länge
count_summary = defaultdict(int)
length_summary = defaultdict(float)
@@ -290,11 +311,11 @@ def write_excel_from_json(plines:Polylines, outpath:str):
ws1.column_dimensions['D'].width = 25
for pl in plines.kabel:
length = pl.length /1000 # Umrechnung von mm in m
length = round(pl.length /1000 , 1) # Umrechnung von mm in m
for artnr in sens2cable[pl.id]:
cable_name = ""
if artnr.isdigit():
cable_name = cable_cfg["Sivasnummern"][artnr]
cable_name = bezeichner_cfg["Sivasnummern"][artnr]
ws1.append([pl.id, length, artnr, cable_name])
if "MA" in pl.id:
@@ -465,53 +486,10 @@ def get_cable_artnr(section, length):
return True, entries[str(l)]
return False, f"Kabel länger als max. Kabellänge in Sektion '{section}'"
def map_sensor_to_cable(plines):
sens2cable = defaultdict(list)
for pl in plines.kabel:
sensor_name = pl.id.split('-')[-1]
cable_length = pl.length/1000
sensor_artinr = pl.s_artinr
name_prefix = sensor_name[0:2]
sections = [] #Default
if name_prefix == "MA":
sections = ["MA"] # Sektion für Motor-Kabel
elif name_prefix == "MB":
sections = ["WD_Q"] # Sektion für Ventil-Kabel
elif name_prefix == "QM":
sections = ["WD_Q"] # Sektion für Ventil-Kabel
elif sensor_name.startswith("B"): # Sensor Name beginnt mit B -> Sensor jeglicher Art
if name_prefix == "BX": # Wenn "BX", dann Scanner
sections = ["WF_B", "WD_I"] # Sektion für Scanner Patch-Kabel und Sektion für Standard-Sensorkabel zur Spannungsversorgung
cable_length = max(0.0, cable_length -4.0) # 4 Meter abziehen, da bereits 5m Kabelschwanz an Scanner dran
elif sensor_artinr == 829422026:
sections = ["WD_I-829422026"]
elif sensor_artinr == 720002003:
sections = ["WD_I-720002003"]
else:
sections = ["WD_I"]
if not sections:
sens2cable[pl.id].append ("Kein Kabeltyp zugewiesen")
continue
for section in sections:
cable_artnr = get_cable_artnr(section, cable_length)
if cable_artnr is None:
sens2cable[pl.id].append(f"Kabel länger als max. Kabellänge")
else:
sens2cable[pl.id].append(cable_artnr)
return sens2cable
def map_sensor_to_cable_cfg(plines):
sens2cable = defaultdict(list)
mapping = config_BMK["Cable-Mapping"]
for pl in plines.kabel:
@@ -540,10 +518,7 @@ def map_sensor_to_cable_cfg(plines):
# Kabel-Atikelnummer innerhalb der Sektion der kabel.cfg bestimmen
for section in sections:
sucess, result = get_cable_artnr(section, cable_length)
if not sucess:
sens2cable[pl.id].append(result)
else:
sens2cable[pl.id].append(result)
sens2cable[pl.id].append(result)
return sens2cable
@@ -588,10 +563,10 @@ if __name__ == '__main__':
config_BMK.optionxform = lambda option: option # preserve case for letters
config_BMK.read(os.path.join(config_dir, "BMK.cfg"))
names_cfg = configparser.ConfigParser()
names_cfg.optionxform = str #Keys case-sensitive
bezeichner_cfg = configparser.ConfigParser()
bezeichner_cfg.optionxform = str #Keys case-sensitive
with open(os.path.join(config_dir, "bezeichner.cfg"), encoding="utf-8") as f:
names_cfg.read_file(f)
bezeichner_cfg.read_file(f)
dxf_file = args.dxf
@@ -626,8 +601,20 @@ if __name__ == '__main__':
res_pos = new_dxf(plines, out_path)
if args.excel:
excel_path = os.path.join(work_dir, args.excel)
export_excel(plines, excel_path)
# 1. Kabelzuordnung
sens2cable = map_sensor_to_cable_cfg(plines)
# 2. verwendete Artikelnummer (Sensoren + Kabel)
all_artnrs = get_all_artnrs(plines, sens2cable)
# 3. Fehlende Bezeichner in bezeichner.cfg markieren
mark_missings(all_artnrs)
# 4. Bezeichner ggf. aus SIVAS abrufen
if args.local == False:
config_path=os.path.join(config_dir, "bezeichner.cfg")
uc.update_bezeichner(bezeichner_cfg, config_path)
# 5. Excel schreiben
excel_path = os.path.join(work_dir, args.excel)
export_excel(plines, sens2cable, excel_path)
+20 -19
View File
@@ -3,22 +3,21 @@ import configparser
import os
import subprocess
import csv
import pandas as pd
def get_sivas_teilestamm(sivas_ids, out_dir=None, overwrite=True):
def get_sivas_teilestamm(sivas_ids, overwrite=True, out_dir= os.environ.get('PROJECT_DATA')):
"""
Generiert für jede angegebene SIVAS-Teilenummer eine CSV-Datei, in der die Teilestamm-Informationen gespeichert sind
"""
sivas_teilestamm_exe = os.environ.get('SIVAS_TEILESTAMM')
if not os.path.isfile(sivas_teilestamm_exe):
raise FileNotFoundError(
f"Programmpfad '{sivas_teilestamm_exe}' nicht erreichbar. "
f"Bitte Zugriff und Variable SIVAS_TEILESTAMM in setenv.bat prüfen."
)
if out_dir is None:
out_dir = os.environ.get('PROJECT_DATA')
if not os.path.isdir(out_dir):
raise NotADirectoryError(
f"Ausgabeverzeichnis '{out_dir}' existiert nicht. "
@@ -51,10 +50,6 @@ def get_sivas_teilestamm(sivas_ids, out_dir=None, overwrite=True):
rows = list(csv_data)
if len(rows) != 2:
raise ValueError(f"SIVAS-Teilenummer '{id}' existiert nicht oder liefert keine gültige CSV.")
# Rückgabe des Bezeichners (zweite Zeile, zweite Spalte)
yield id, rows[1][1].strip()
def read_bezeichner_from_csv(teilenr):
"""
@@ -64,28 +59,32 @@ def read_bezeichner_from_csv(teilenr):
:return: Bezeichner-String, falls erfolgreich. Wirft Exception bei Fehler.
"""
csv_dir = os.environ.get("PROJECT_DATA", ".")
csv_path = os.path.join(csv_dir, f"{teilenr}.csv")
if not os.path.isfile(csv_path):
raise FileNotFoundError(f"CSV für Teilenummer '{teilenr}' nicht gefunden unter {csv_path}")
with open(csv_path, encoding="utf-8", newline="") as f:
reader = csv.reader(f, delimiter=";")
rows = list(reader)
if len(rows) != 2:
raise ValueError(f"Ungültiges Format oder keine Daten in CSV für '{teilenr}'")
try:
df = pd.read_csv(csv_path, sep=";", encoding="utf-8")
except Exception as e:
raise ValueError(f"Fehler beim Einlesen der CSV: {e}")
bezeichner = rows[1][1].strip()
return bezeichner
if df.shape[0] != 1:
raise ValueError(f"Ungültiger Zeileninhalt für '{teilenr}' erwartet genau eine Datenzeile.")
if "Bezeichnung1" not in df.columns:
raise ValueError(f"Spalte 'Bezeichnung1' nicht gefunden in CSV für '{teilenr}'.")
return str(df["Bezeichnung1"].iloc[0]).strip()
def update_bezeichner(names_config):
def update_bezeichner(names_config, config_path):
if "Missing" not in names_config or not names_config["Missing"]:
print("Keine fehlenden Einträge in [Missing]. Keine Abfrage angestoßen.")
return
missing_ids = list(names_config["Missing"].keys())
resolved_ids = []
print(f"Starte SIVAS-Abfrage für {len(missing_ids)} fehlende Teilenummer(n)...")
@@ -93,20 +92,22 @@ def update_bezeichner(names_config):
get_sivas_teilestamm(missing_ids)
except Exception as e:
print(f"Fehler bei der SIVAS-Abfrage: {e}")
return
updated = 0
for id in missing_ids:
try:
bezeichner = read_bezeichner_from_csv(id)
if "Sivasnummern" not in names_config:
names_config["Sivasnummern"] = {}
names_config["Sivasnummern"][id] = bezeichner
resolved_ids.append(id)
updated += 1
except Exception as e:
print(f"WARNUNG: Bezeichner für {id} konnte nicht gelesen werden: {e}")
for id in missing_ids:
for id in resolved_ids:
names_config["Missing"].pop(id, None)
if "Missing" in names_config and not names_config["Missing"]: