This commit is contained in:
Benny Megidish
2024-12-05 20:31:19 +02:00
6 changed files with 132 additions and 11 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
.venv
dist/
.DS_Store
.DS_Store
*.pyc
+29
View File
@@ -171,6 +171,35 @@ _The fields will be queried in the order denoted above._
_The fields will be queried in the order denoted above._
## CLI-Usage
The plugin can also be used via the linux commandline. This can be particularly useful if you need to embed the plugin into an automation pipeline or environment.
The plugin can be called with the command below:
```
python3 -m plugins.cli -p /myProject/myBoard.kicad_pcb
```
The all options from the GUI are also available via the cli interface:
```
python3 -m plugins.cli -h
usage: Fabrication Toolkit [-h] --path PATH [--additionalLayers ADDITIONALLAYERS] [--user1VCut] [--user2AltVCut] [--autoTranslate] [--autoFill]
[--excludeDNP] [--allActiveLayers] [--openBrowser]
Generates JLCPCB production files from a KiCAD board file
options:
-h, --help show this help message and exit
--path PATH, -p PATH Path to KiCAD board file
--additionalLayers ADDITIONALLAYERS, -aL ADDITIONALLAYERS Additional layers(comma-separated)
--user1VCut, -u1 Set User.1 as V-Cut layer
--user2AltVCut, -u2 Use User.2 for alternative Edge-Cut layer
--autoTranslate, -t Apply automatic position/rotation translations
--autoFill, -f Apply automatic fill for all zones
--excludeDNP, -e Exclude DNP components from BOM
--allActiveLayers, -aaL Export all active layers instead of only commonly used ones
--openBrowser, -b Open webbrowser with directory file overview after generation
```
## Author
+36
View File
@@ -0,0 +1,36 @@
import argparse as ap
from .thread import ProcessThread
from .options import *
if __name__ == '__main__':
parser = ap.ArgumentParser(prog="Fabrication Toolkit",
description="Generates JLCPCB production files from a KiCAD board file")
parser.add_argument("--path", "-p", type=str, help="Path to KiCAD board file", required=True)
parser.add_argument("--additionalLayers", "-aL", type=str, help="Additional layers(comma-separated)")
parser.add_argument("--user1VCut", "-u1", action="store_true", help="Set User.1 as V-Cut layer")
parser.add_argument("--user2AltVCut", "-u2", action="store_true", help="Use User.2 for alternative Edge-Cut layer")
parser.add_argument("--autoTranslate", "-t", action="store_true", help="Apply automatic position/rotation translations")
parser.add_argument("--autoFill", "-f", action="store_true", help="Apply automatic fill for all zones")
parser.add_argument("--excludeDNP", "-e", action="store_true", help="Exclude DNP components from BOM")
parser.add_argument("--allActiveLayers", "-aaL",action="store_true", help="Export all active layers instead of only commonly used ones")
parser.add_argument("--openBrowser", "-b", action="store_true", help="Open webbrowser with directory file overview after generation")
args = parser.parse_args()
options = dict()
options[AUTO_TRANSLATE_OPT] = args.autoTranslate
options[AUTO_FILL_OPT] = args.autoFill
options[EXCLUDE_DNP_OPT] = args.excludeDNP
options[EXTEND_EDGE_CUT_OPT] = args.user1VCut
options[ALTERNATIVE_EDGE_CUT_OPT] = args.user2AltVCut
options[ALL_ACTIVE_LAYERS_OPT] = args.allActiveLayers
options[EXTRA_LAYERS] = args.additionalLayers
openBrowser = args.openBrowser
path = args.path
ProcessThread(wx=None, cli=path, options=options, openBrowser=openBrowser)
+6 -2
View File
@@ -18,8 +18,12 @@ from .utils import footprint_has_field, footprint_get_field, get_plot_plan
from .config import *
class ProcessManager:
def __init__(self):
self.board = pcbnew.GetBoard()
def __init__(self, board = None):
# if no board is already loaded by cli mode getBoard from kicad environment
if board is None:
self.board = pcbnew.GetBoard()
else:
self.board = board
self.bom = []
self.components = []
self.__rotation_db = self.__read_rotation_db()
+37 -8
View File
@@ -5,20 +5,38 @@ import shutil
import tempfile
import webbrowser
import datetime
import logging
from threading import Thread
from .events import StatusEvent
from .process import ProcessManager
from .config import *
from .options import *
from .utils import print_cli_progress_bar
class ProcessThread(Thread):
def __init__(self, wx, options):
def __init__(self, wx, options, cli = None, openBrowser = True):
Thread.__init__(self)
self.process_manager = ProcessManager()
# prevent use of cli and grapgical mode at the same time
if (wx is None and cli is None) or (wx is not None and cli is not None):
logging.error("Specify either graphical or cli use!")
return
if cli is not None:
try:
self.board = pcbnew.LoadBoard(cli)
except Exception as e:
logging.error("Fabrication Toolkit - Error" + str(e))
return
else:
self.board = None
self.process_manager = ProcessManager(self.board)
self.wx = wx
self.cli = cli
self.options = options
self.openBrowser = openBrowser
self.start()
def run(self):
@@ -70,7 +88,10 @@ class ProcessThread(Thread):
shutil.rmtree(temp_dir_gerber)
temp_file = os.path.join(temp_dir, os.path.basename(temp_file))
except Exception as e:
wx.MessageBox(str(e), "Fabrication Toolkit - Error", wx.OK | wx.ICON_ERROR)
if self.wx is None:
logging.error("Fabrication Toolkit - Error" + str(e))
else:
wx.MessageBox(str(e), "Fabrication Toolkit - Error", wx.OK | wx.ICON_ERROR)
self.progress(-1)
return
@@ -118,12 +139,20 @@ class ProcessThread(Thread):
# copy to & open output dir
try:
shutil.copytree(temp_dir, output_path, dirs_exist_ok=True)
webbrowser.open("file://%s" % (output_path))
if self.openBrowser:
webbrowser.open("file://%s" % (output_path))
shutil.rmtree(temp_dir)
except Exception as e:
webbrowser.open("file://%s" % (temp_dir))
except Exception as e:
if self.openBrowser:
webbrowser.open("file://%s" % (temp_dir))
self.progress(-1)
if self.wx is None:
self.progress(100)
else:
self.progress(-1)
def progress(self, percent):
wx.PostEvent(self.wx, StatusEvent(percent))
if self.wx is None:
print_cli_progress_bar(percent, prefix = 'Progress:', suffix = 'Complete', length = 50)
else:
wx.PostEvent(self.wx, StatusEvent(percent))
+22
View File
@@ -77,3 +77,25 @@ def get_layer_names(board, active_only=True):
"""Returns a list of (active) layer names of the current board"""
plotPlan = get_plot_plan(board, active_only)
return [layer_info[0] for layer_info in plotPlan]
def print_cli_progress_bar(percent, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"):
"""
Call in a loop to create terminal progress bar string
@params:
percent - Required : current percentage (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : positive number of decimals in percent complete (Int)
length - Optional : character length of bar (Int)
fill - Optional : bar fill character (Str)
printEnd - Optional : end character (e.g. "\r", "\r\n") (Str)
"""
if percent == -1:
percent = 0
filledLength = int(length * (percent / 100 ))
bar = fill * filledLength + '-' * (length - filledLength)
percent2dec = "%.2f" % percent
print(f'\r{prefix} |{bar}| {percent2dec}% {suffix}', end = printEnd)
# Print New Line on Complete
if percent == 100:
print()