commit 156fbb9db12fc0dcc0ab9f4b579d8bbaf5d3aa42 Author: sirlilpanda Date: Wed Dec 31 02:25:00 2025 +1300 init diff --git a/.hooks/config.json b/.hooks/config.json new file mode 100644 index 0000000..21c57fe --- /dev/null +++ b/.hooks/config.json @@ -0,0 +1,18 @@ +{ + "kicad_project_search_path": "hardware/", + "schematic_output_path": "docs/", + "bom_csv_output_path": "docs/BOM/", + "bom_report_output_path": "docs/BOM/", + "production_file_output_path": "pcbs/", + "schematic_output_name": "_schematic", + "bom_csv_output_name": "_bill_of_materials", + "bom_report_output_name": "_bom_report", + "production_file_output_name": "_gerber", + "template_paths" : { + "bom": ".github/report_templates/bom_report_template.mustache", + "erc_report": ".github/report_templates/erc_report_template.mustache", + "drc_report": ".github/report_templates/drc_report_template.mustache", + "readme": ".github/report_templates/readme.mustache" + }, + "dynamic_read_me": true +} \ No newline at end of file diff --git a/.hooks/main.py b/.hooks/main.py new file mode 100644 index 0000000..37d0335 --- /dev/null +++ b/.hooks/main.py @@ -0,0 +1,173 @@ +# 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: + 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, + ) + + # look i dont know what you want to do + # but here you go + def create_3d_model(self) -> None: + ... + + # 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 export_pcb(self) -> None: + ... + + def download_datasheets(self) -> None: + ... + + +class Report: + + def export() -> str: + ... + +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() + print(k.erc_check(return_report=True)) + print(k.process_bom(return_csv=True)) + k.create_schmatic_pdf() + k.create_pcb_pdf() + k.get_image() + + + + + print("hello world"); + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/test_pcb.pdf b/docs/test_pcb.pdf new file mode 100644 index 0000000..92e8f53 Binary files /dev/null and b/docs/test_pcb.pdf differ diff --git a/docs/test_schematic.pdf b/docs/test_schematic.pdf new file mode 100644 index 0000000..072b657 Binary files /dev/null and b/docs/test_schematic.pdf differ diff --git a/drc.json b/drc.json new file mode 100644 index 0000000..2c87716 --- /dev/null +++ b/drc.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://schemas.kicad.org/drc.v1.json", + "coordinate_units": "mm", + "date": "2025-12-31T01:11:53+1300", + "kicad_version": "9.0.6", + "schematic_parity": [], + "source": "test.kicad_pcb", + "unconnected_items": [], + "violations": [ + { + "description": "Board has malformed outline (no edges found on Edge.Cuts layer)", + "items": [ + { + "description": "PCB", + "pos": { + "x": 0.0, + "y": 0.0 + }, + "uuid": "7690956f-7cf1-4850-b24e-2c34f81a5616" + } + ], + "severity": "error", + "type": "invalid_outline" + } + ] +} diff --git a/hardware/test/test.kicad_pcb b/hardware/test/test.kicad_pcb new file mode 100644 index 0000000..c547853 --- /dev/null +++ b/hardware/test/test.kicad_pcb @@ -0,0 +1,2 @@ +(kicad_pcb (version 20241229) (generator "pcbnew") (generator_version "9.0") +) \ No newline at end of file diff --git a/hardware/test/test.kicad_pro b/hardware/test/test.kicad_pro new file mode 100644 index 0000000..f8c65e3 --- /dev/null +++ b/hardware/test/test.kicad_pro @@ -0,0 +1,32 @@ +{ + "board": { + "design_settings": { + "defaults": {}, + "diff_pair_dimensions": [], + "drc_exclusions": [], + "rules": {}, + "track_widths": [], + "via_dimensions": [] + } + }, + "boards": [], + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "kicad.kicad_pro", + "version": 1 + }, + "net_settings": { + "classes": [], + "meta": { + "version": 0 + } + }, + "pcbnew": { + "page_layout_descr_file": "" + }, + "sheets": [], + "text_variables": {} +} diff --git a/hardware/test/test.kicad_sch b/hardware/test/test.kicad_sch new file mode 100644 index 0000000..5bc70ed --- /dev/null +++ b/hardware/test/test.kicad_sch @@ -0,0 +1,14 @@ +(kicad_sch + (version 20250114) + (generator "eeschema") + (generator_version "9.0") + (uuid f507f841-113f-488d-81ff-25ffa9ae803f) + (paper "A4") + (lib_symbols) + (sheet_instances + (path "/" + (page "1") + ) + ) + (embedded_fonts no) +) \ No newline at end of file diff --git a/res/test_render.png b/res/test_render.png new file mode 100644 index 0000000..e2dbc32 Binary files /dev/null and b/res/test_render.png differ diff --git a/temp/test_drc.csv b/temp/test_drc.csv new file mode 100644 index 0000000..bc40a48 --- /dev/null +++ b/temp/test_drc.csv @@ -0,0 +1 @@ +"Refs","Value","Footprint","Qty","DNP" diff --git a/temp/test_drc.json b/temp/test_drc.json new file mode 100644 index 0000000..2dc73d1 --- /dev/null +++ b/temp/test_drc.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://schemas.kicad.org/drc.v1.json", + "coordinate_units": "mm", + "date": "2025-12-31T02:13:27+1300", + "kicad_version": "9.0.6", + "schematic_parity": [], + "source": "test.kicad_pcb", + "unconnected_items": [], + "violations": [ + { + "description": "Board has malformed outline (no edges found on Edge.Cuts layer)", + "items": [ + { + "description": "PCB", + "pos": { + "x": 0.0, + "y": 0.0 + }, + "uuid": "11ba8380-b107-4944-a66d-39eb5d745a00" + } + ], + "severity": "error", + "type": "invalid_outline" + } + ] +} diff --git a/temp/test_erc.json b/temp/test_erc.json new file mode 100644 index 0000000..0835bfd --- /dev/null +++ b/temp/test_erc.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://schemas.kicad.org/erc.v1.json", + "coordinate_units": "mm", + "date": "2025-12-31T02:13:27+1300", + "kicad_version": "9.0.6", + "sheets": [ + { + "path": "/", + "uuid_path": "/f507f841-113f-488d-81ff-25ffa9ae803f", + "violations": [] + } + ], + "source": "test.kicad_sch" +}