Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7733b50609 | |||
| 4ad8357a7e | |||
| dbf3a6450d |
+137
-15
@@ -48,6 +48,11 @@ class Polylines:
|
|||||||
errors_existing_dists: List[str]
|
errors_existing_dists: List[str]
|
||||||
errors_existing_sensors: List[str]
|
errors_existing_sensors: List[str]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Sensors:
|
||||||
|
name: str
|
||||||
|
artinr: str
|
||||||
|
pos: List[float]
|
||||||
|
|
||||||
def add_polyline(msp, points:Polyline, dxf_attribs):
|
def add_polyline(msp, points:Polyline, dxf_attribs):
|
||||||
pts = points.to_tuple()
|
pts = points.to_tuple()
|
||||||
@@ -238,7 +243,6 @@ def draw_subdists(plines, doc):
|
|||||||
text.dxf.valign = valign
|
text.dxf.valign = valign
|
||||||
text.set_placement((pt1.x + offsetx, pt1.y + offsety))
|
text.set_placement((pt1.x + offsetx, pt1.y + offsety))
|
||||||
|
|
||||||
|
|
||||||
def model_from_json(json_file):
|
def model_from_json(json_file):
|
||||||
with open(json_file, encoding='utf-8') as fh:
|
with open(json_file, encoding='utf-8') as fh:
|
||||||
data = json.load(fh)
|
data = json.load(fh)
|
||||||
@@ -249,36 +253,72 @@ def model_from_json(json_file):
|
|||||||
)
|
)
|
||||||
return plines
|
return plines
|
||||||
|
|
||||||
|
def parse_sensors_from_json(positions_json):
|
||||||
|
with open(positions_json, encoding='utf-8') as fh:
|
||||||
|
data = json.load(fh)
|
||||||
|
|
||||||
|
sensors = {}
|
||||||
|
for name, data in data.get("sensors", {}).items():
|
||||||
|
sensor = Sensors(
|
||||||
|
name=name,
|
||||||
|
artinr=data.get("ARTINR", ""),
|
||||||
|
pos=data.get("pos", [0.0, 0.0]),
|
||||||
|
)
|
||||||
|
sensors[name] = sensor
|
||||||
|
return sensors
|
||||||
|
|
||||||
def export_excel(json_file, out_path):
|
def export_excel(json_file, out_path):
|
||||||
# Hier für Excel Export
|
# Hier für Excel Export
|
||||||
print("creating excel file with cable information ..")
|
print("creating excel file with cable information ..")
|
||||||
plines = model_from_json(json_file)
|
plines = model_from_json(json_file)
|
||||||
write_excel_from_json(plines, out_path)
|
sens2cable = map_sensor_to_cable(sensors, plines)
|
||||||
|
write_excel_from_json(plines, sens2cable, out_path)
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
def write_excel_from_json(plines:Polylines, outpath:str):
|
def write_excel_from_json(plines:Polylines, sens2cable: dict, outpath:str):
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
length_summary = defaultdict(int)
|
|
||||||
|
|
||||||
#Worksheet 1 - Kabellängen
|
# Dicts für Anzahl bzw kummulierte Länge
|
||||||
|
count_summary = defaultdict(int)
|
||||||
|
length_summary = defaultdict(float)
|
||||||
|
|
||||||
|
#Worksheet 1 - Kabellängen nach Kabel-ID
|
||||||
ws1 = wb.active
|
ws1 = wb.active
|
||||||
ws1.title = "Length by ID"
|
ws1.title = "Length by ID"
|
||||||
ws1.append(["Cable-ID", "True Length (m)", "Rounded Length (m)"])
|
ws1.append(["Cable-ID", "True Length (m)", "Cable-ArtNr"])
|
||||||
|
|
||||||
for pl in plines.kabel:
|
for pl in plines.kabel:
|
||||||
length = pl.length /1000 # Umrechnung von mm in m
|
length = pl.length /1000 # Umrechnung von mm in m
|
||||||
rounded_len = math.ceil(length/5)*5
|
artnr = sens2cable[pl.id]
|
||||||
length_summary[rounded_len] +=1
|
ws1.append([pl.id, length, artnr])
|
||||||
ws1.append([pl.id, length, int(rounded_len)])
|
|
||||||
|
|
||||||
# Worksheet 2 - Zusammengefasste Längen
|
if "MA" in pl.id:
|
||||||
ws2 = wb.create_sheet("Length Summary")
|
length_summary[artnr] += math.ceil(length) # Aufrunden von z.b. 10,3 auf 11 m (volle Meter!)
|
||||||
ws2.append(["Rounded Length (m)", "Number of Cables"])
|
|
||||||
|
|
||||||
for rlength in sorted(length_summary):
|
|
||||||
ws2.append([int(rlength), length_summary[rlength]])
|
|
||||||
|
|
||||||
|
# MB als Motor gesetzt! Beachte auch Zuordnung in get_cable_artnr!!
|
||||||
|
|
||||||
|
elif "MB" in pl.id: # MB statt MA zur Motor-Kennzeichnung
|
||||||
|
length_summary[artnr] += math.ceil(length) # Aufrunden von z.b. 10,3 auf 11 m (volle Meter!)
|
||||||
|
|
||||||
|
else:
|
||||||
|
count_summary[artnr] += 1
|
||||||
|
|
||||||
|
# Worksheet 2 - Kabelnummern und Stückzahlen
|
||||||
|
ws2 = wb.create_sheet("Cables SIVAS")
|
||||||
|
ws2.append(["Cable-ArtNr", "Ammount / total length"])
|
||||||
|
|
||||||
|
all_artnrs = set(count_summary.keys()) | set(length_summary.keys())
|
||||||
|
|
||||||
|
for artnr in sorted(all_artnrs):
|
||||||
|
count = count_summary.get(artnr, "")
|
||||||
|
if count == "":
|
||||||
|
count = length_summary.get(artnr, "")
|
||||||
|
ws2.append([artnr, count])
|
||||||
|
|
||||||
|
# Abfage ob Fehler Worsheets ausgegeben werden
|
||||||
if len(plines.errors_existing_sensors) > 0 or len(plines.errors_dists) > 0:
|
if len(plines.errors_existing_sensors) > 0 or len(plines.errors_dists) > 0:
|
||||||
|
|
||||||
# Worksheet 3 - Nicht an Racks gekoppeltes Equipment
|
# Worksheet 3 - Nicht an Racks gekoppeltes Equipment
|
||||||
ws3 = wb.create_sheet("Not connected Equipment")
|
ws3 = wb.create_sheet("Not connected Equipment")
|
||||||
ws3.append(["Type", "ID", "x", "y"])
|
ws3.append(["Type", "ID", "x", "y"])
|
||||||
@@ -388,10 +428,78 @@ def copy_layers_into_dxf_by_filter(dxf_source: ezdxf.document.Drawing, dxf_targe
|
|||||||
for entity in entities:
|
for entity in entities:
|
||||||
msp_target.add_entity(entity.copy())
|
msp_target.add_entity(entity.copy())
|
||||||
|
|
||||||
|
def get_cable_artnr(section, length):
|
||||||
|
"""
|
||||||
|
Sucht in der angegebenen Config-Section die passende Kabel-Artikelnr. für die gegebene Länge.
|
||||||
|
"""
|
||||||
|
if section not in cable_cfg:
|
||||||
|
return None
|
||||||
|
|
||||||
|
entries = cable_cfg[section]
|
||||||
|
|
||||||
|
# Alle Einträge der Form: "5" = "123456789"
|
||||||
|
try:
|
||||||
|
length_keys = sorted(
|
||||||
|
[float(k) for k in entries.keys() if k.replace('.', '', 1).isdigit()]
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for l in length_keys:
|
||||||
|
if length <= l:
|
||||||
|
return entries[str(int(l))] # Annahme: Keys sind ganze Zahlen in Metern
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def map_sensor_to_cable(sensors, plines):
|
||||||
|
sens2cable = defaultdict()
|
||||||
|
for pl in plines.kabel:
|
||||||
|
# Sensorname von Kabel-ID extraieren
|
||||||
|
sensor_name = pl.id.split('-')[-1]
|
||||||
|
# Kabellänge aus gleichem Eintrag auslesen + in m umrechnen
|
||||||
|
cable_length = pl.length/1000
|
||||||
|
|
||||||
|
# Sensor Artikelnummer aus positions.json holen
|
||||||
|
sensor_artinr = sensors[sensor_name].artinr
|
||||||
|
|
||||||
|
# Verzweigung, um welchen Typ es sich handelt (Special Keys)
|
||||||
|
name_prefix = sensor_name[0:2]
|
||||||
|
|
||||||
|
section = None #Default
|
||||||
|
|
||||||
|
if name_prefix == "MA" or name_prefix == "MB":
|
||||||
|
section = "MA"
|
||||||
|
|
||||||
|
elif name_prefix == "QM":
|
||||||
|
section = "WD_Q"
|
||||||
|
|
||||||
|
elif sensor_name.startswith("B"):
|
||||||
|
if sensor_artinr == 829422026:
|
||||||
|
section = "WD_I-829422026"
|
||||||
|
elif sensor_artinr == 720002003:
|
||||||
|
section = "WD_I-720002003"
|
||||||
|
else:
|
||||||
|
section = "WD_I"
|
||||||
|
|
||||||
|
if section is None:
|
||||||
|
cable_artnr = "KEIN KABEL"
|
||||||
|
else:
|
||||||
|
cable_artnr = get_cable_artnr(section, cable_length)
|
||||||
|
if cable_artnr is None:
|
||||||
|
cable_artnr = "KEIN KABEL"
|
||||||
|
|
||||||
|
sens2cable[pl.id] = cable_artnr
|
||||||
|
|
||||||
|
return sens2cable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser(description='draws a dxf file with the given cable coordinates', prog='drawdxf')
|
parser = argparse.ArgumentParser(description='draws a dxf file with the given cable coordinates', prog='drawdxf')
|
||||||
parser.add_argument('-f', '--filename', action='store', required=True, help='this json file contains all cables and its coordinates which should be drawn. Saved with an unique timestamp', metavar='myfile.json')
|
parser.add_argument('-f', '--filename', action='store', required=True, help='this json file contains all cables and its coordinates which should be drawn. Saved with an unique timestamp', metavar='myfile.json')
|
||||||
|
parser.add_argument('-p','--positions', action='store', required=True, help='this json file contains positional information written by getpositions', metavar='myfile.json')
|
||||||
parser.add_argument('-d', '--dxf', action='store', help='this dxf drawing will be copied and the new layer with the cables will be added. Original file must be added with --origin', metavar='myfile.dxf')
|
parser.add_argument('-d', '--dxf', action='store', help='this dxf drawing will be copied and the new layer with the cables will be added. Original file must be added with --origin', metavar='myfile.dxf')
|
||||||
parser.add_argument('-c', '--copy_layer', action='store', help='copy layers of racks, sensors, distributors into a new .dxf-file. File also contains cable paths. Original file must be added with --origin', metavar='original.dxf')
|
parser.add_argument('-c', '--copy_layer', action='store', help='copy layers of racks, sensors, distributors into a new .dxf-file. File also contains cable paths. Original file must be added with --origin', metavar='original.dxf')
|
||||||
parser.add_argument('-n', '--new', action='store', help='create a new dxf file only with cables in it. Name is basename and a timestamp')
|
parser.add_argument('-n', '--new', action='store', help='create a new dxf file only with cables in it. Name is basename and a timestamp')
|
||||||
@@ -403,6 +511,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
config_dir = os.environ.get("PROJECT_CFG")
|
config_dir = os.environ.get("PROJECT_CFG")
|
||||||
work_dir = os.fspath(os.environ.get('PROJECT_WORK'))
|
work_dir = os.fspath(os.environ.get('PROJECT_WORK'))
|
||||||
|
|
||||||
json_file = args.filename
|
json_file = args.filename
|
||||||
(json_path, jexists) = check_file_in_work(work_dir, json_file)
|
(json_path, jexists) = check_file_in_work(work_dir, json_file)
|
||||||
if not jexists:
|
if not jexists:
|
||||||
@@ -410,14 +519,27 @@ if __name__ == '__main__':
|
|||||||
parser.print_help()
|
parser.print_help()
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
|
positions_json = args.positions
|
||||||
|
(positions_path, jexists) = check_file_in_work(work_dir, positions_json)
|
||||||
|
if not jexists:
|
||||||
|
print(f"file {positions_json} does not exist")
|
||||||
|
parser.print_help()
|
||||||
|
exit()
|
||||||
|
|
||||||
plines = model_from_json(json_path)
|
plines = model_from_json(json_path)
|
||||||
|
sensors = parse_sensors_from_json(positions_path)
|
||||||
|
|
||||||
|
|
||||||
|
# Allgemeine Config laden
|
||||||
config = configparser.ConfigParser(allow_no_value=True, delimiters=("="))
|
config = configparser.ConfigParser(allow_no_value=True, delimiters=("="))
|
||||||
config.optionxform = lambda option: option # preserve case for letters
|
config.optionxform = lambda option: option # preserve case for letters
|
||||||
|
|
||||||
config.read(os.path.join(config_dir, "allgemein.cfg"))
|
config.read(os.path.join(config_dir, "allgemein.cfg"))
|
||||||
|
|
||||||
|
# Config für Kabel-Atikelnummern laden
|
||||||
|
cable_cfg = configparser.ConfigParser()
|
||||||
|
cable_cfg.optionxform = str #Keys case-sensitive
|
||||||
|
cable_cfg.read(os.path.join(config_dir, "kabel.cfg"))
|
||||||
|
|
||||||
dxf_file = args.dxf
|
dxf_file = args.dxf
|
||||||
|
|
||||||
if args.dxf or args.copy_layer:
|
if args.dxf or args.copy_layer:
|
||||||
|
|||||||
+11
-3
@@ -42,6 +42,7 @@ def get_type_of_name(name):
|
|||||||
"MA", # Motor
|
"MA", # Motor
|
||||||
"BG", # Stausensor
|
"BG", # Stausensor
|
||||||
"BP" # Schalter Druckluft
|
"BP" # Schalter Druckluft
|
||||||
|
"QM" # Ventile
|
||||||
]
|
]
|
||||||
|
|
||||||
KabelKey = ["WD"]
|
KabelKey = ["WD"]
|
||||||
@@ -71,7 +72,6 @@ def get_type_of_name(name):
|
|||||||
return typ
|
return typ
|
||||||
|
|
||||||
def get_attributes_of_insert(insert):
|
def get_attributes_of_insert(insert):
|
||||||
|
|
||||||
id = ""
|
id = ""
|
||||||
ld = dict()
|
ld = dict()
|
||||||
typ = 'unknown'
|
typ = 'unknown'
|
||||||
@@ -94,6 +94,8 @@ def get_attributes_of_insert(insert):
|
|||||||
# Suche nach Sensoren
|
# Suche nach Sensoren
|
||||||
typ = get_type_of_name(attr_text)
|
typ = get_type_of_name(attr_text)
|
||||||
id = attr_text
|
id = attr_text
|
||||||
|
pos = attrib.dxf.insert #Position aufzeichnen und bei Bedarf später mit REAL_POS überschreiben
|
||||||
|
ld["pos"] = (round(pos.x, 1), round(pos.y, 1))
|
||||||
|
|
||||||
if attr_tag == "REALE_POSITION" and attr_text == "x":
|
if attr_tag == "REALE_POSITION" and attr_text == "x":
|
||||||
#typ = get_type_of_name(attr_text)
|
#typ = get_type_of_name(attr_text)
|
||||||
@@ -179,10 +181,14 @@ def create_mappings(positions:dict) -> dict:
|
|||||||
sensor2unterverteiler = dict()
|
sensor2unterverteiler = dict()
|
||||||
warnings = list()
|
warnings = list()
|
||||||
for sensorname,v in positions.items():
|
for sensorname,v in positions.items():
|
||||||
|
if "KENNZEICHNUNG" not in v:
|
||||||
|
warnings.append(f"{sensorname}: keine KENNZEICHNUNG vorhanden")
|
||||||
|
continue
|
||||||
|
|
||||||
unterverteiler_pfad = v["KENNZEICHNUNG"]
|
unterverteiler_pfad = v["KENNZEICHNUNG"]
|
||||||
#print(unterverteiler_pfad)
|
#print(unterverteiler_pfad)
|
||||||
|
|
||||||
# PFad zur Karte splitten. Dieser hat z.B. den Inhalt "=AH01+UH02-KF1FDI7"
|
# Pfad zur Karte splitten. Dieser hat z.B. den Inhalt "=AH01+UH02-KF1FDI7"
|
||||||
pattern = r"^=([A-Z]+\d+)([+\-])([A-Z]+\d+)([+\-])([A-Z0-9]+)$"
|
pattern = r"^=([A-Z]+\d+)([+\-])([A-Z]+\d+)([+\-])([A-Z0-9]+)$"
|
||||||
match = re.match(pattern, unterverteiler_pfad)
|
match = re.match(pattern, unterverteiler_pfad)
|
||||||
if match:
|
if match:
|
||||||
@@ -198,8 +204,9 @@ def create_mappings(positions:dict) -> dict:
|
|||||||
warnings.append(unterverteiler_pfad)
|
warnings.append(unterverteiler_pfad)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not verteiler in dnamen:
|
if verteiler not in dnamen:
|
||||||
dnamen[verteiler] = True
|
dnamen[verteiler] = True
|
||||||
|
|
||||||
sensor2unterverteiler[sensorname] = verteiler
|
sensor2unterverteiler[sensorname] = verteiler
|
||||||
|
|
||||||
# jetzt zu jedem Unterverteiler die zugehörigen Sensoren merken
|
# jetzt zu jedem Unterverteiler die zugehörigen Sensoren merken
|
||||||
@@ -208,6 +215,7 @@ def create_mappings(positions:dict) -> dict:
|
|||||||
if verteiler not in uv2sensor:
|
if verteiler not in uv2sensor:
|
||||||
uv2sensor[verteiler] = list()
|
uv2sensor[verteiler] = list()
|
||||||
uv2sensor[verteiler].append(sensorname)
|
uv2sensor[verteiler].append(sensorname)
|
||||||
|
|
||||||
return (uv2sensor, warnings)
|
return (uv2sensor, warnings)
|
||||||
|
|
||||||
def get_subdistributor_positions(msp, dist2sensors):
|
def get_subdistributor_positions(msp, dist2sensors):
|
||||||
|
|||||||
@@ -449,8 +449,6 @@ class Anlage():
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def join_racks(self):
|
def join_racks(self):
|
||||||
self._racks.join_racks_str()
|
self._racks.join_racks_str()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user