# yes we are using json because # i dont want to install a yaml # parser on the users computer import json import os import subprocess import csv from enum import Enum from pathlib import Path from os import listdir from os.path import isfile, join KICAD_CLI_PATH = "kicad-cli" TEMP_FILE_PATH = "temp/" PCB_IMAGE_OUTPUT_PATH = "res/" PCB_PDF_OUTPUT_PATH = "docs/" PCB_PDF_FILE_SUFFIX = "_pcb" SCHEMATIC_OUTPUT_PATH = "docs/" SCHEMATIC_FILE_SUFFIX = "_schematic" TEMP_DRC_REPORT_NAME = "_drc" TEMP_ERC_REPORT_NAME = "_erc" TEMP_BOM_REPORT_NAME = "_bom" class OutputReportType(Enum): JSON = 1 RPT = 2 # this is a thin vale on the kicad cli tool class KicadProject: def __init__(self, path : Path) -> None: self.project_path = path.parent self.project_name = path.name.removesuffix(".kicad_pro") print(f"{self.project_path=}") print(f"{self.project_name=}") def erc_check( self, report_format : OutputReportType = OutputReportType.JSON, return_report : bool = False ) -> None | dict | str: format_type = report_format.name.lower() pcb_file_path = self.project_path / f"{self.project_name}.kicad_sch" erc_report_path = Path(TEMP_FILE_PATH) / f"{self.project_name}{TEMP_ERC_REPORT_NAME}.{format_type}" subprocess.call( f'{KICAD_CLI_PATH} sch erc {pcb_file_path} --output {erc_report_path} --format {format_type}', shell=True, ) if (return_report): with open(erc_report_path, "r") as txt: if format_type == OutputReportType.JSON: return json.loads(txt.read()) if format_type == OutputReportType.RPT: return txt.read() def drc_check( self, report_format : OutputReportType = OutputReportType.JSON, return_report : bool = False ) -> None | dict | str: format_type = report_format.name.lower() pcb_file_path = self.project_path / f"{self.project_name}.kicad_pcb" drc_report_path = Path(TEMP_FILE_PATH) / f"{self.project_name}{TEMP_DRC_REPORT_NAME}.{format_type}" subprocess.call( f'{KICAD_CLI_PATH} pcb drc {pcb_file_path} --output {drc_report_path} --format {format_type}', shell=True, ) if (return_report): with open(drc_report_path, "r") as txt: if format_type == OutputReportType.JSON: return json.loads(txt.read()) if format_type == OutputReportType.RPT: return txt.read() def process_bom(self, return_csv : bool = False) -> None | list[list[str]]: sch_file_path = self.project_path / f"{self.project_name}.kicad_sch" bom_output_path = Path(TEMP_FILE_PATH) / f"{self.project_name}{TEMP_DRC_REPORT_NAME}.csv" subprocess.call( f'{KICAD_CLI_PATH} sch export bom {sch_file_path} --output {bom_output_path}', shell=True, ) if (return_csv): with open(bom_output_path, "r") as csvfile: bom_csv = csv.reader(csvfile, delimiter=',', quotechar='"') return [row for row in bom_csv] def get_image(self, image_type : str = "png", height : int = 900, width : int = 1600, side : str = "top", background : str = "default", preset : str = "follow_pcb_editor", zoom : int = 2, ) -> None: """ image_typ = "png" | "jpg" side = "top" | "bottom" | "left" | "right" | "front" | "back" background = "default" | "transparent" | "opaque" """ pcb_file_path = self.project_path / f"{self.project_name}.kicad_pcb" render_output_path = Path(PCB_IMAGE_OUTPUT_PATH) / f"{self.project_name}_render.{image_type}" subprocess.call( f'{KICAD_CLI_PATH} pcb render {pcb_file_path} --output {render_output_path} --preset {preset} --zoom {zoom} ', shell=True, ) # i am not giving you the pdf to output if you want to do that yourself go ahead def create_schmatic_pdf(self) -> None: sch_file_path = self.project_path / f"{self.project_name}.kicad_sch" sch_report_path = Path(SCHEMATIC_OUTPUT_PATH) / f"{self.project_name}{SCHEMATIC_FILE_SUFFIX}.pdf" subprocess.call( f'{KICAD_CLI_PATH} sch export pdf {sch_file_path} --output {sch_report_path}', shell=True, ) def create_pcb_pdf(self, layers : list[str] = ["F.Cu", "B.Cu"]) -> None: pcb_file_path = self.project_path / f"{self.project_name}.kicad_pcb" pcb_report_path = Path(PCB_PDF_OUTPUT_PATH) / f"{self.project_name}{PCB_PDF_FILE_SUFFIX}.pdf" subprocess.call( f'{KICAD_CLI_PATH} pcb export pdf {pcb_file_path} --output {pcb_report_path} --layers {",".join(layers)}', shell=True, ) def main() -> None: # find all kicad project files to operate on for path in Path(".").rglob('*.kicad_pro'): print(path.name) print(path) print(type(path.parent)) k = KicadProject(path) k.drc_check() k.erc_check() k.process_bom() k.create_schmatic_pdf() k.create_pcb_pdf() k.get_image() print("hello world"); if __name__ == "__main__": main()