diff --git a/docs/usage/examples.rst b/docs/usage/examples.rst index 5fe2967..66522ea 100644 --- a/docs/usage/examples.rst +++ b/docs/usage/examples.rst @@ -144,4 +144,296 @@ This example shows how a schematic symbol might be added from a symbol library i schematic.schematicSymbols.append(schematic_symbol) # Save the schematic to a file - schematic.to_file('path_to_save_schematic.kicad_sch') \ No newline at end of file + schematic.to_file('path_to_save_schematic.kicad_sch') + + +Importing Mouser Schematics/footprints/models .zips to Kicad +-------------------- +you'll need an extra python file colored_terminal.py +.. code-block:: python + # Small libary to add some colors to the consol output as well as a last line clear function + # import with: from colored_terminal import * + import sys + + def print_with_color(color_code, *args, indent=0): + if indent: + indent = " " * indent + else: + indent = "" + print(f"\033[{color_code}m{indent}", end="") + print(*args, end="") + print("\033[0m", end="") + sys.stdout.flush() + + + def print_yellow(*args, indent = 0): + print_with_color("33", *args, indent=indent) + + + def print_black(*args, indent = 0): + print_with_color("30", *args, indent=indent) + + + def print_red(*args, indent = 0): + print_with_color("31", *args, indent=indent) + + + def print_green(*args, indent = 0): + print_with_color("32", *args, indent=indent) + + + def print_blue(*args, indent = 0): + print_with_color("34", *args, indent=indent) + + + def print_magenta(*args, indent = 0): + print_with_color("35", *args, indent=indent) + + + def print_cyan(*args, indent = 0): + print_with_color("36", *args, indent=indent) + + + def print_white(*args, indent = 0): + print_with_color("37", *args, indent=indent) + + + def clear_console_line(): + """clears the last line in the console""" + print("\033[2K\033[G", end="", flush=True) + +here goes the main code: +.. code-block:: python + from pathlib import Path + from kiutils.symbol import SymbolLib # https://kiutils.readthedocs.io/en/latest/module/kiutils.html#kiutils.footprint.Footprint.position + from kiutils.footprint import Footprint# https://kiutils.readthedocs.io/en/latest/module/kiutils.html#kiutils.footprint.Footprint.position + from kiutils.items.common import Position + import sys + import re + import zipfile + import shutil + from colored_terminal import * + + if __name__ == '__main__': + print_magenta("\n\n") + + # handles argvs + if len(sys.argv) != 3: + print_yellow(f" too little arguments: ({len(sys.argv)})\n") + print_yellow(" start this tool with these arguments:\n") + print_yellow(" [path_zip] [path_libary_folder]\n") + sys.exit() + + PATH_ZIP = Path(sys.argv[1]) # path to zip where symbols to copy are + PATH_LIBRARY_DIR = Path(sys.argv[2]) # path to libary where footprint should go + PATH_LIBRARY_SYMBOLS = Path() # path to simbol libary + PATH_LIBARY_PRETTY = Path() #path to footprint.pretty in libary + PATH_TEMP_DIR = PATH_LIBRARY_DIR / "temporary" # temporaty folder to export ZIP to + PATH_SYMBOL_2COPY = Path() # path to symbols which y wanna copy + + print_magenta(f'>extracting zip\n') + # Extract zip contents to temporary directory + with zipfile.ZipFile(PATH_ZIP, "r") as zip_ref: + zip_ref.extractall(PATH_TEMP_DIR) + print("\n",end='') + + print_magenta(f'>searching for target symbol/footprints\n') + # search for a kicad symbol libary + sym_dirs = list(PATH_LIBRARY_DIR.rglob("*.kicad_sym")) + print_cyan(f' target symbol libary:') + if len(sym_dirs): + PATH_LIBRARY_SYMBOLS = sym_dirs[0] + print_white(f'"{sym_dirs[0]}"\n') + else: + if PATH_TEMP_DIR.exists() and PATH_TEMP_DIR.is_dir(): + shutil.rmtree(PATH_TEMP_DIR) + raise Exception("ERROR: Not found") + + # search for a footprint folder + pretty_dirs = [ + p for p in PATH_LIBRARY_DIR.rglob("*") if p.is_dir() and p.name.endswith(".pretty") + ] + print_cyan(f' target footprints:') + if len(pretty_dirs): + # found footprint folder + print_white(f' "{pretty_dirs[0]}"\n') + PATH_LIBARY_PRETTY = pretty_dirs[0] + else: + # creates footprint folder + PATH_LIBARY_PRETTY = PATH_LIBRARY_DIR / (PATH_SYMBOL_2COPY.stem + ".pretty") + PATH_LIBARY_PRETTY.mkdir(parents=True, exist_ok=True) + print_white(f'created "{PATH_LIBARY_PRETTY}"\n') + + # search for a source kicad symbol libary in Source + sym_dirs = list(PATH_TEMP_DIR.rglob("*.kicad_sym")) + print_cyan(f' source symbol libary:') + if len(sym_dirs): + PATH_SYMBOL_2COPY = sym_dirs[0] + print_white(f'"{sym_dirs[0]}"\n') + else: + if PATH_TEMP_DIR.exists() and PATH_TEMP_DIR.is_dir(): + shutil.rmtree(PATH_TEMP_DIR) + raise Exception("Nothing found\n") + print("\n",end='') + + print_magenta(f'>copying symbol libary\n') + # copys Symbol to libary + # print(PATH_SYMBOL_2COPY) + symbolLibrary = SymbolLib.from_file(PATH_LIBRARY_SYMBOLS) + symbolToCopy = SymbolLib.from_file(PATH_SYMBOL_2COPY) + + print_cyan(f" length target symbol libary: {len(symbolLibrary.symbols)}\n") + + for symbol in symbolToCopy.symbols: + print_cyan(f' found symbol to insert: ') + print_white(f'"{symbol.entryName}"\n') + if any(s.entryName == symbol.entryName for s in symbolLibrary.symbols): + print_yellow("-> already in the library. Skipping.\n") + else: + print("-> writes symbol to libary") + symbolLibrary.symbols.append(symbolToCopy.symbols[0]) + + # overwrites existing libary + print_cyan(f' new length of target libary: {len(symbolLibrary.symbols)}\n') + symbolLibrary.to_file(PATH_LIBRARY_SYMBOLS) + print("\n",end='') + + print_magenta(f'>Copying footprint\n') + # copys Footprint + print_cyan(f' copies footprint:') + for model_file in PATH_TEMP_DIR.rglob("*.kicad_mod"): + print(f'"{model_file.name}"') + fp = Footprint.from_file(model_file) # load from source + for model in fp.models: + print_white(f' -adjusted 3D model path') + print_white(f' from "{model.path}" | ') + model.path = "${KIPRJMOD}/libary/3D/" + model.path + print_white(f'to "{model.path}"') + dest_path = PATH_LIBARY_PRETTY / model_file.name + fp.to_file(dest_path) + print("\n",end='') + print("\n",end='') + + print_magenta(f'>Copying 3D files\n') + PATH_LIBARY_3D_DIR = PATH_LIBRARY_DIR / "3D" + PATH_LIBARY_3D_DIR.mkdir(parents=True, exist_ok=True) + foundOne = False + print_cyan(f' copies 3D_model:') + # print_yellow(f'path: "{PATH_TEMP_DIR}"\n') + for model_file in PATH_TEMP_DIR.rglob("*.stp"): + print(f'"{model_file.name}"',end='') + shutil.copy2(model_file, PATH_LIBARY_3D_DIR / model_file.name) + foundOne = True + if not foundOne: + print_red(f' didn t found a 3D model') + print("\n",end='') + print("\n",end='') + + # deletes temp + print_magenta("\n") + if len(sys.argv) != 3: + if not (len((sys.argv)) >= 3 and int(sys.argv[2]) == -1): + print(f"too little arguments: ({len(sys.argv)})") + print("start this tool with these arguments:") + print("[libary_path] [nr_symbol]") + print("- filepath to libary") + print( + "- choose [number] wich simbols pins y wanna regroup. Set to -1 to just show the list" + ) + sys.exit() + + # Load the symbol library + filepath = sys.argv[1] + lib = SymbolLib.from_file(filepath) + + print_cyan("Found Symbols:\n") + # Print available symbols + for nr, symbol in enumerate(lib.symbols): + print(f" [{nr}] Symbol name: {symbol.entryName}") + + # select symbol from libary + number = sys.argv[2] + if not number.isnumeric(): + print("please enter number") + sys.exit() + if int(number) == -1: + sys.exit() + selectedIc = lib.symbols[int(number)] + + print_cyan("Selected IC:\n") + print(f"Symbol name: {selectedIc.entryName}") + print(f"Amount of pins: {len(selectedIc.pins)}") + if len(selectedIc.pins) == 0: + print_red( + f'Error:\n\ + go to {filepath}\n\ + find {selectedIc.entryName}\n\ + go to pin section\n\ + delete (above pins) the complete line "(symbol "{selectedIc.entryName} (in_bom yes) (on_board yes)"\n\ + as well as the matching brackets at the end.\n' + ) + sys.exit() + sys.exit() + print("Properties:") + for prop in selectedIc.properties: + print(f" {prop.key} = {prop.value}") + + # groups pins + PinDictory = {} + for pin in selectedIc.pins: + groupName = pin.name[:3] # grouping logic + if groupName not in PinDictory: + PinDictory[groupName] = [] + PinDictory[groupName].append(pin) + + # sort groups + def natural_key(pin): + # extract prefix letters and numeric suffix for sorting + match = re.match(r"([a-zA-Z]+)(\d+)", pin.name) + if match: + prefix, num = match.groups() + return (prefix, int(num)) + else: + return (pin.name, 0) # fallback + + sortedPinDictionary = {} + for groupName, pinList in PinDictory.items(): + pinList.sort(key=natural_key) + sortedPinDictionary[groupName] = pinList + PinDictory = sortedPinDictionary + + # # changes coordinates from these pins + for x, (groupName, pinList) in enumerate(PinDictory.items()): + # try: + for y, pin in enumerate(pinList): + pin.position.X = x * SPACE_BETWEEN_PIN_X + pin.position.Y = -y * SPACE_BETWEEN_PIN_Y - SPACE_BETWEEN_PIN_Y + pin.position.angle = 0 + + # saved modified file + filepath = sys.argv[1] + lib.to_file(filepath) + + print_yellow("conversion succesful\n")