From 156fbb9db12fc0dcc0ab9f4b579d8bbaf5d3aa42 Mon Sep 17 00:00:00 2001 From: sirlilpanda Date: Wed, 31 Dec 2025 02:25:00 +1300 Subject: [PATCH] init --- .hooks/config.json | 18 ++++ .hooks/main.py | 173 +++++++++++++++++++++++++++++++++++ README.md | 0 docs/test_pcb.pdf | Bin 0 -> 2579 bytes docs/test_schematic.pdf | Bin 0 -> 10672 bytes drc.json | 26 ++++++ hardware/test/test.kicad_pcb | 2 + hardware/test/test.kicad_pro | 32 +++++++ hardware/test/test.kicad_sch | 14 +++ res/test_render.png | Bin 0 -> 5667 bytes temp/test_drc.csv | 1 + temp/test_drc.json | 26 ++++++ temp/test_erc.json | 14 +++ 13 files changed, 306 insertions(+) create mode 100644 .hooks/config.json create mode 100644 .hooks/main.py create mode 100644 README.md create mode 100644 docs/test_pcb.pdf create mode 100644 docs/test_schematic.pdf create mode 100644 drc.json create mode 100644 hardware/test/test.kicad_pcb create mode 100644 hardware/test/test.kicad_pro create mode 100644 hardware/test/test.kicad_sch create mode 100644 res/test_render.png create mode 100644 temp/test_drc.csv create mode 100644 temp/test_drc.json create mode 100644 temp/test_erc.json 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 0000000000000000000000000000000000000000..92e8f5365ba5e2261d9423173d29c123d70b7dc4 GIT binary patch literal 2579 zcmb_eO>Y}T7|x+wh6`LMNE}{-(%Mq$*;!}((K;3J7o^RHWhbPPZK3gc9B;MRU3O=q z1QZF1K$H{LUic4)Bd1FI04`kk2dIC7cV^e?jZ+mNWe@i3JMZ_`v+KQf_Z}-*Wc{0O zpM6IxFu&Gv9FW>(0H!w-(pI-Op-=BT|%dgL0Jb%%w-~Qpl_ug&2_0FxIK6(GiUu$cB zy!zl35#BV_gC}KP+0_3`-KkSGbBxf#i$DPF@e@JtHx!-(rko_SFCsq#1x z3w?VaBn&AA3iME%OQ1WaDBDW^o8yGD>!Ti1>(P==4kk~9EupMPDpa~BrVelV=P)#o zR@-EyTD<~R-71;&%9zj=YCvZqP+9B~6iJ=0;kyc=(VzpMpZbSB&^8QJOggi2oMUE6 zdBP2}$s?g1qn`=)Oi0J(%G)#r>PEi~;)&ErQK?~?)bX%Hj&}m|*zvZ#$XO8brc~PA zVCvq%#C5)m#Z8)28Ge(=rteN~(w-{cf7!eFFqcuPSb#pp!cBD{b$R*S0Mk z-viaJOG!Krpg?A^m)s8Kd!qvHcrtWEG%CW^THhHDf#Y2A(+IX;IDVk1Ge3k;LESmv zcyLWhMV?BPf;gIw3W+vFSC6e6zMshro$=5ZZ)nvC1G4mmj6?4#6HCTh@m!9In*Wky ze%h_M@7MzU21%6&^b+J_X$PMcm2=P^y>Ph+9x- z-!~1@VrH2cCM%n@1p{_xq1S5ecaD*A=tviNrHJGgfjub&(-~5?V>wrBc*K3Hu>sG^ zFzVT~Wg5DrR*b!(pi1=tN-pp!fe5+{3LElR!SWEC%;G^TUB^qN6+tG+0roRuau`Wa zcJ)G`yF7bcy2Tb?ijbJ%MvF`C`X|bp6U53CJUaXFe*DxI`e1`IMg~lv|*;U$W^p!0{>8pIKR=GwqHVxd=SNROfxb92E#8j>D zRm)hSt29=iuw1TW$Z;S;{q;6*zQUfX0`2=g&P@6hx8u!xV7gk#*BcL| Pu8GO4I$2-u9CXRQ2;Rtf literal 0 HcmV?d00001 diff --git a/docs/test_schematic.pdf b/docs/test_schematic.pdf new file mode 100644 index 0000000000000000000000000000000000000000..072b65706d52ae76c0d1c3274636f0e4f31302ff GIT binary patch literal 10672 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 LheuWCI_Q4@$znj; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e2dbc32dbb1068687d0d42cc23c928e0d6019c76 GIT binary patch literal 5667 zcmeAS@N?(olHy`uVBq!ia0y~yU{hdVV9wxR1B!U+C}{&JmSQK*5Dp-y;YjIVU=Y3K z>EaktG3U+AgS?J`3@#V_bzH6_u4NX@n3mzlIO{?~M@y^Px;;nimp9$?duPH3G+`8s zhQMeDjE2By2#kinXb6mkz-S0i7y|a&C2WC4Jj*G+G5^}_vxQ&!>PvRV{FP;3kjSvC zf*Agxo`nO{eGrW@ukK$>k&MvWK^3kHUP zNf&vhpp<;(=JUTh_sgCC`~sM|N5N