#!/usr/bin/env python3 """Fertigungsdaten: Gerber+Bohrdaten (zip), Stückliste mit Inventar-Fächern, Schaltplan-PDF, 1:1-Druck, Doku-Bilder.""" import os, sys, csv, shutil, subprocess, zipfile, collections HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) from design import PARTS, PROJECT FAB = os.path.join(HERE, 'fab'); G = os.path.join(FAB, 'gerber') shutil.rmtree(G, ignore_errors=True); os.makedirs(G) pcb = os.path.join(HERE, PROJECT + '.kicad_pcb'); sch = os.path.join(HERE, PROJECT + '.kicad_sch') def run(*a): subprocess.run(a, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) run('kicad-cli', 'pcb', 'export', 'gerbers', '-o', G + '/', '--layers', 'F.Cu,B.Cu,F.Silkscreen,B.Silkscreen,F.Mask,B.Mask,Edge.Cuts', '--subtract-soldermask', pcb) run('kicad-cli', 'pcb', 'export', 'drill', '-o', G + '/', '--format', 'excellon', '--excellon-separate-th', pcb) zp = os.path.join(FAB, PROJECT + '_gerber.zip') with zipfile.ZipFile(zp, 'w', zipfile.ZIP_DEFLATED) as z: for f in sorted(os.listdir(G)): z.write(os.path.join(G, f), f) run('kicad-cli', 'sch', 'export', 'pdf', '-o', os.path.join(FAB, PROJECT + '_schaltplan.pdf'), sch) run('kicad-cli', 'pcb', 'export', 'pdf', '--mode-single', '-l', 'F.Silkscreen,F.Fab,Edge.Cuts,F.Courtyard', '--include-border-title', '-o', os.path.join(FAB, PROJECT + '_1zu1_druck.pdf'), pcb) # ---------- Stückliste ---------- INV = { # (Wert, Footprint-Teil) -> Inventar-Fach (Parts_Inventory.xlsx) '100': 'E-01-3', '220': 'E-05-3', '330': 'E-07-3', '470': 'E-09-3', '1k': 'E-01-4', '2k2': 'E-05-4', '4k7': 'E-09-4', '10k': 'E-01-5', '100n': 'C-07-1', '10u': 'C-10-2 / D-04-3', '470u/10V': 'C-04-3', '1000u/10V': 'C-05-3', 'BC546B': 'B-01-4', '1N4007': 'B-02-1', 'LED grün': 'B-07-5', 'LED rot': 'B-08-5', 'Pull-up 5V': 'A-07-2 + Jumper A-11-3', 'ERWEITERUNG': 'A-07-2', 'SRD-05VDC-SL-C': 'A-07-1 prüfen (sonst kaufen)', 'T 2A': 'Clips/Halter B-12-2, Sicherung B-11-2', 'WEMOS D1 mini': 'Buchsenleisten A-06-5 / A-07-3', 'ADS1115 Modul': 'Buchsenleiste A-06-5; Modul ggf. B-11-5', 'MAX6675 Modul': 'Buchsenleiste A-06-5; Modul ggf. B-11-5', } BUY = {'ZMCT103C': 'kaufen (Stromwandler 5A/5mA)', 'MAX6675 Modul': 'kaufen inkl. Thermoelement Typ K (Abgasfühler)', 'ADS1115 Modul': 'kaufen, falls kein Rest von der Umwälzpumpe', 'WEMOS D1 mini': 'vorhanden/kaufen'} rows = collections.OrderedDict() for p in PARTS: if p.get('board') is False or p['ref'].startswith('H'): continue key = (p['val'], p['fp'].split(':')[-1]) rows.setdefault(key, []).append(p) with open(os.path.join(FAB, PROJECT + '_bom.csv'), 'w', newline='') as f: w = csv.writer(f, delimiter=';') w.writerow(['Anzahl', 'Referenzen', 'Wert', 'Footprint', 'Inventar-Fach', 'Beschaffung / Hinweis']) for (val, fp), ps in rows.items(): refs = ' '.join(sorted((q['ref'] for q in ps), key=lambda r: (r.rstrip('0123456789'), int(''.join(c for c in r if c.isdigit()) or 0)))) term = ps[0]['fp'].startswith('Connector_Phoenix') inv = '' if term else INV.get(val, '') hint = ps[0].get('mpn') or BUY.get(val, '') w.writerow([len(ps), refs, val, fp, inv, hint]) print('fab ok:', sorted(os.listdir(FAB)))