Kicad addon WIP

This commit is contained in:
jaseg 2025-12-09 19:22:47 +01:00
parent 7590bde619
commit ce74278bf6
11 changed files with 1135 additions and 79 deletions

10
kicad-plugin/__init__.py Normal file
View file

@ -0,0 +1,10 @@
from pathlib import Path
from kipy import KiCad
from kipy.errors import ConnectionError
import kicoil.gui
if __name__ == '__main__':
kicad_inst = KiCad()
kicoil.gui.main(kicad_inst)

BIN
kicad-plugin/icon-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

406
kicad-plugin/icon-dark.svg Normal file
View file

@ -0,0 +1,406 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="12.5mm"
height="12.5mm"
viewBox="-19.823074 -22.198258 12.5 12.5"
version="1.1"
id="svg38"
sodipodi:docname="icon-dark.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
inkscape:export-filename="icon.png"
inkscape:export-xdpi="130.048"
inkscape:export-ydpi="130.048"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs38" />
<sodipodi:namedview
id="namedview38"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="6.4840427"
inkscape:cx="-1.5422477"
inkscape:cy="-5.6292041"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg38" />
<rect
style="fill:#1b111f;fill-opacity:1;stroke:none;stroke-width:1.41685;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="rect38"
width="12.5"
height="12.5"
x="-19.823074"
y="-22.198257" />
<g
id="g62"
transform="matrix(0.28523786,0,0,0.28523786,-14.168783,-15.866474)">
<path
d="m 8.5867713,5.8416089 a 8.22617,8.22617 0 0 1 -1.80878,5.3403601"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path38"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 6.7779913,11.181969 a 10.7975,10.7975 0 0 1 -4.68641,3.40964"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path39"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 2.0915813,14.591609 a 13.2639,13.2639 0 0 1 -8.23249,0.31"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path40"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -6.1409087,14.901609 a 15.8862,15.8862 0 0 1 -6.9229103,-4.06"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path41"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -4.4036087,5.8416089 a 8.22617,8.22617 0 0 1 -3.72051,-4.236633"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path42"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -8.1241187,1.6049759 a 10.7975,10.7975 0 0 1 -0.6096,-5.763367"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path43"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -8.7337187,-4.1583911 a 13.2639,13.2639 0 0 1 3.84776,-7.2844999"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path44"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -4.8859587,-11.442891 a 15.8862,15.8862 0 0 1 6.97754,-3.9655"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path45"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 2.0915813,-5.4083911 a 8.22617,8.22617 0 0 1 5.52928,-1.10373"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path46"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 7.6208613,-6.5121211 a 10.7975,10.7975 0 0 1 5.2960197,2.35373"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path47"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 12.916881,-4.1583911 a 13.2639,13.2639 0 0 1 4.3847,6.974543"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path48"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 17.301581,2.8161519 a 15.8862,15.8862 0 0 1 -0.0546,8.0254571"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path49"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 2.0915813,-15.408391 a 15.5807,15.5807 0 0 1 7.9867397,5.0724"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path50"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 10.078321,-10.335991 a 12.9547,12.9547 0 0 1 2.83856,6.1775999"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path51"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 12.916881,-4.1583911 a 10.4951,10.4951 0 0 1 -1.06364,6.715005"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path52"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="M 11.853241,2.5566139 A 7.92896,7.92896 0 0 1 8.5867713,5.8416089"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path53"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 17.246981,10.841609 a 15.5807,15.5807 0 0 1 -8.3861397,4.3805"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path54"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 8.8608413,15.222109 a 12.9547,12.9547 0 0 1 -6.76926,-0.6305"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path55"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 2.0915813,14.591609 a 10.4951,10.4951 0 0 1 -5.28354,-4.27866"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path56"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -3.1919587,10.312949 a 7.92896,7.92896 0 0 1 -1.21165,-4.4713401"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path57"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -13.063819,10.841609 a 15.5807,15.5807 0 0 1 0.3994,-9.4529151"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path58"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -12.664419,1.3886939 a 12.9547,12.9547 0 0 1 3.9307003,-5.547085"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path59"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -8.7337187,-4.1583911 a 10.4951,10.4951 0 0 1 6.34718,-2.43635"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path60"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -2.3865387,-6.5947411 a 7.92896,7.92896 0 0 1 4.47812,1.18635"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path61"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
</g>
<g
id="g38"
style="mix-blend-mode:multiply"
transform="matrix(0.28523786,0,0,0.28523786,-14.168783,-15.866474)">
<g
stroke-linejoin="round"
stroke-linecap="round"
id="l-bottom-copper"
transform="matrix(0,-1,-1,0,2.0915813,2.0916089)"
opacity="0.7"
style="opacity:1;fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1">
<path
d="m -3.75,-6.49519 a 8.22617,8.22617 0 0 0 -5.34036,1.80878"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path1"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M -9.09036,-4.68641 A 10.7975,10.7975 0 0 0 -12.5,0"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path2"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -12.5,0 a 13.2639,13.2639 0 0 0 -0.31,8.23249"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path3"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -12.81,8.23249 a 15.8862,15.8862 0 0 0 4.06,6.92291"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path4"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M -3.75,6.49519 A 8.22617,8.22617 0 0 0 0.486633,10.2157"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path5"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 0.486633,10.2157 A 10.7975,10.7975 0 0 0 6.25,10.8253"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path6"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 6.25,10.8253 A 13.2639,13.2639 0 0 0 13.5345,6.97754"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path7"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 13.5345,6.97754 A 15.8862,15.8862 0 0 0 17.5,0"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path8"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 7.5,0 A 8.22617,8.22617 0 0 0 8.60373,-5.52928"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path9"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 8.60373,-5.52928 A 10.7975,10.7975 0 0 0 6.25,-10.8253"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path10"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 6.25,-10.8253 A 13.2639,13.2639 0 0 0 -0.724543,-15.21"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path11"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M -0.724543,-15.21 A 15.8862,15.8862 0 0 0 -8.75,-15.1554"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path12"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
stroke-linejoin="round"
stroke-linecap="round"
id="l-top-copper"
transform="matrix(0,-1,-1,0,2.0915813,2.0916089)"
opacity="0.7"
style="opacity:1;mix-blend-mode:color-dodge;fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none">
<path
d="M 17.5,0 A 15.5807,15.5807 0 0 0 12.4276,-7.98674"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path17"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 12.4276,-7.98674 A 12.9547,12.9547 0 0 0 6.25,-10.8253"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path18"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="m 6.25,-10.8253 a 10.4951,10.4951 0 0 0 -6.715005,1.06364"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path19"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -0.465005,-9.76166 A 7.92896,7.92896 0 0 0 -3.75,-6.49519"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path20"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="m -8.75,-15.1554 a 15.5807,15.5807 0 0 0 -4.3805,8.38614"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path21"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -13.1305,-6.76926 A 12.9547,12.9547 0 0 0 -12.5,0"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path22"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="m -12.5,0 a 10.4951,10.4951 0 0 0 4.27866,5.28354"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path23"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -8.22134,5.28354 A 7.92896,7.92896 0 0 0 -3.75,6.49519"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path24"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -8.75,15.1554 A 15.5807,15.5807 0 0 0 0.702915,14.756"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path25"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 0.702915,14.756 A 12.9547,12.9547 0 0 0 6.25,10.8253"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path26"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 6.25,10.8253 A 10.4951,10.4951 0 0 0 8.68635,4.47812"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path27"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 8.68635,4.47812 A 7.92896,7.92896 0 0 0 7.5,0"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path28"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

BIN
kicad-plugin/icon-light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

406
kicad-plugin/icon-light.svg Normal file
View file

@ -0,0 +1,406 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="12.5mm"
height="12.5mm"
viewBox="-19.823074 -22.198258 12.5 12.5"
version="1.1"
id="svg38"
sodipodi:docname="icon-light.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
inkscape:export-filename="icon-light.png"
inkscape:export-xdpi="130.048"
inkscape:export-ydpi="130.048"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs38" />
<sodipodi:namedview
id="namedview38"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="6.4840427"
inkscape:cx="-1.5422477"
inkscape:cy="-5.6292041"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg38" />
<rect
style="fill:#f2eff2;fill-opacity:1;stroke:none;stroke-width:1.41685;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
id="rect38"
width="12.5"
height="12.5"
x="-19.823074"
y="-22.198257" />
<g
id="g62"
transform="matrix(0.28523786,0,0,0.28523786,-14.168783,-15.866474)">
<path
d="m 8.5867713,5.8416089 a 8.22617,8.22617 0 0 1 -1.80878,5.3403601"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path38"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 6.7779913,11.181969 a 10.7975,10.7975 0 0 1 -4.68641,3.40964"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path39"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 2.0915813,14.591609 a 13.2639,13.2639 0 0 1 -8.23249,0.31"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path40"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -6.1409087,14.901609 a 15.8862,15.8862 0 0 1 -6.9229103,-4.06"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path41"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -4.4036087,5.8416089 a 8.22617,8.22617 0 0 1 -3.72051,-4.236633"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path42"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -8.1241187,1.6049759 a 10.7975,10.7975 0 0 1 -0.6096,-5.763367"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path43"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -8.7337187,-4.1583911 a 13.2639,13.2639 0 0 1 3.84776,-7.2844999"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path44"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -4.8859587,-11.442891 a 15.8862,15.8862 0 0 1 6.97754,-3.9655"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path45"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 2.0915813,-5.4083911 a 8.22617,8.22617 0 0 1 5.52928,-1.10373"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path46"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 7.6208613,-6.5121211 a 10.7975,10.7975 0 0 1 5.2960197,2.35373"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path47"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 12.916881,-4.1583911 a 13.2639,13.2639 0 0 1 4.3847,6.974543"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path48"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 17.301581,2.8161519 a 15.8862,15.8862 0 0 1 -0.0546,8.0254571"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path49"
style="opacity:1;mix-blend-mode:normal;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 2.0915813,-15.408391 a 15.5807,15.5807 0 0 1 7.9867397,5.0724"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path50"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 10.078321,-10.335991 a 12.9547,12.9547 0 0 1 2.83856,6.1775999"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path51"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 12.916881,-4.1583911 a 10.4951,10.4951 0 0 1 -1.06364,6.715005"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path52"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="M 11.853241,2.5566139 A 7.92896,7.92896 0 0 1 8.5867713,5.8416089"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path53"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 17.246981,10.841609 a 15.5807,15.5807 0 0 1 -8.3861397,4.3805"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path54"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 8.8608413,15.222109 a 12.9547,12.9547 0 0 1 -6.76926,-0.6305"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path55"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m 2.0915813,14.591609 a 10.4951,10.4951 0 0 1 -5.28354,-4.27866"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path56"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -3.1919587,10.312949 a 7.92896,7.92896 0 0 1 -1.21165,-4.4713401"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path57"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -13.063819,10.841609 a 15.5807,15.5807 0 0 1 0.3994,-9.4529151"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path58"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -12.664419,1.3886939 a 12.9547,12.9547 0 0 1 3.9307003,-5.547085"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path59"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -8.7337187,-4.1583911 a 10.4951,10.4951 0 0 1 6.34718,-2.43635"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path60"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<path
d="m -2.3865387,-6.5947411 a 7.92896,7.92896 0 0 1 4.47812,1.18635"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path61"
style="opacity:1;mix-blend-mode:lighten;fill:none;stroke:#ffffff;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
</g>
<g
id="g38"
style="mix-blend-mode:multiply"
transform="matrix(0.28523786,0,0,0.28523786,-14.168783,-15.866474)">
<g
stroke-linejoin="round"
stroke-linecap="round"
id="l-bottom-copper"
transform="matrix(0,-1,-1,0,2.0915813,2.0916089)"
opacity="0.7"
style="opacity:1;fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1">
<path
d="m -3.75,-6.49519 a 8.22617,8.22617 0 0 0 -5.34036,1.80878"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path1"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M -9.09036,-4.68641 A 10.7975,10.7975 0 0 0 -12.5,0"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path2"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -12.5,0 a 13.2639,13.2639 0 0 0 -0.31,8.23249"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path3"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m -12.81,8.23249 a 15.8862,15.8862 0 0 0 4.06,6.92291"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path4"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M -3.75,6.49519 A 8.22617,8.22617 0 0 0 0.486633,10.2157"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path5"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 0.486633,10.2157 A 10.7975,10.7975 0 0 0 6.25,10.8253"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path6"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 6.25,10.8253 A 13.2639,13.2639 0 0 0 13.5345,6.97754"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path7"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 13.5345,6.97754 A 15.8862,15.8862 0 0 0 17.5,0"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path8"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 7.5,0 A 8.22617,8.22617 0 0 0 8.60373,-5.52928"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path9"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 8.60373,-5.52928 A 10.7975,10.7975 0 0 0 6.25,-10.8253"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path10"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M 6.25,-10.8253 A 13.2639,13.2639 0 0 0 -0.724543,-15.21"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path11"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
<path
d="M -0.724543,-15.21 A 15.8862,15.8862 0 0 0 -8.75,-15.1554"
fill="none"
stroke="#5c5ceb"
stroke-width="3.0"
id="path12"
style="fill:none;stroke:#0179ff;stroke-width:5;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
stroke-linejoin="round"
stroke-linecap="round"
id="l-top-copper"
transform="matrix(0,-1,-1,0,2.0915813,2.0916089)"
opacity="0.7"
style="opacity:1;mix-blend-mode:color-dodge;fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none">
<path
d="M 17.5,0 A 15.5807,15.5807 0 0 0 12.4276,-7.98674"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path17"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 12.4276,-7.98674 A 12.9547,12.9547 0 0 0 6.25,-10.8253"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path18"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="m 6.25,-10.8253 a 10.4951,10.4951 0 0 0 -6.715005,1.06364"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path19"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -0.465005,-9.76166 A 7.92896,7.92896 0 0 0 -3.75,-6.49519"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path20"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="m -8.75,-15.1554 a 15.5807,15.5807 0 0 0 -4.3805,8.38614"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path21"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -13.1305,-6.76926 A 12.9547,12.9547 0 0 0 -12.5,0"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path22"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="m -12.5,0 a 10.4951,10.4951 0 0 0 4.27866,5.28354"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path23"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -8.22134,5.28354 A 7.92896,7.92896 0 0 0 -3.75,6.49519"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path24"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M -8.75,15.1554 A 15.5807,15.5807 0 0 0 0.702915,14.756"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path25"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 0.702915,14.756 A 12.9547,12.9547 0 0 0 6.25,10.8253"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path26"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 6.25,10.8253 A 10.4951,10.4951 0 0 0 8.68635,4.47812"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path27"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
<path
d="M 8.68635,4.47812 A 7.92896,7.92896 0 0 0 7.5,0"
fill="none"
stroke="#eb5c5c"
stroke-width="3"
id="path28"
style="fill:none;stroke:#ff0000;stroke-width:5;stroke-dasharray:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

22
kicad-plugin/plugin.json Normal file
View file

@ -0,0 +1,22 @@
{
"$schema": "https://go.kicad.org/api/schemas/v1",
"identifier": "de.jaseg.kicoil",
"name": "KiCoil",
"description": "Planar inductor supporting spiral coils, toroidal coils, and hybrids",
"runtime": {
"type": "python",
"min_version": 3.13
},
"actions": [
{
"identifier": "kicoil-generator",
"name": "KiCoil Planar Inductor Generator",
"description": "Generates planar spiral inductors, toroidal inductors, and hybrids thereof",
"show-button": true,
"scopes": ["pcb"],
"entrypoint": "kicoil_plugin_action.py",
"icons-light": ["icon-light.png"],
"icons-dark": ["icon-dark.png"]
}
]
}

View file

@ -1,7 +1,7 @@
{
"$schema": "https://go.kicad.org/pcm/schemas/v1",
"name": "KiCoil",
"description": "A planar inductor for KiCad",
"description": "Planar inductor supporting spiral coils, toroidal coils, and hybrids",
"description_full": "KiCoil generates planar inductors as footprints. Currently, circular spiral and toroid inductors are supported. KiCoil supports arbitrary intermediates between spiral and toroid inductors. By playing around with this, you can create inductors that have lower parasitics and higher self-resonant frequency than standard multilayer spiral inductors.",
"identifier": "de.jaseg.kicoil",
"type": "plugin",
@ -11,7 +11,7 @@
"web": "https://jaseg.de/"
}
},
"license": "GPL-3.0",
"license": "Apache-2.0",
"resources": {
"homepage": "https://jaseg.de/projects/kicoil",
"git": "https://git.jaseg.de/kicoil",
@ -21,8 +21,75 @@
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "8.00"
"kicad_version": "9.00",
"download_sha256": "e0696023ef669b1d4efac3a5cb47abb859db32dca1e3f5efd55344daa848a2be",
"download_size": 70143,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 196790
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "280139c454396d0afaa71ac7bd35c6c09c3c602c3ad55e77b14b51f22df16818",
"download_size": 70143,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 196790
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "3cf67dff3226ca5f3eb2409f5230b4bb02f5266351621b9e97c80493cc48ae61",
"download_size": 69827,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 196790
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "ae1144223256c1f59fad76c27dbdfa3722a16df162b9c3d13cd4e840481626e7",
"download_size": 69103,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 195410
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "429d93b5850bd54a767b5a18fa841c8b17ed30823568d934706d67dca38e1eb1",
"download_size": 69108,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 195414
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "538f89db2c4beef1c344260634b0b6f07c0ba7cb3a81fd71a9a9af028a5c38fe",
"download_size": 69703,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 196520
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "55a3a05e5730713c3456b45e6c8bca5f66e407944d1a465949547a3d5a2b7007",
"download_size": 72082,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 202369
},
{
"version": "0.9.0",
"status": "stable",
"kicad_version": "9.00",
"download_sha256": "736bd91edabc24fa1f342e98e56fa03796363f7e8240adeaaa461bd130ab7c57",
"download_size": 72070,
"download_url": "https://git.jaseg.de/kimesh.git/plain/de.jaseg.kicoil-v0.9.0.zip?h=v0.9.0",
"install_size": 202424
}
],
"runtime": "ipc"
}
}

View file

@ -15,8 +15,9 @@ def tree_size(path):
@click.option('--major', 'increment', flag_value='major')
@click.option('--minor', 'increment', flag_value='minor', default=True)
@click.option('--patch', 'increment', flag_value='patch', default=True)
@click.option('--dry-run', is_flag=True)
@click.argument('version', required=False)
def do_release(version, increment):
def do_release(version, increment, dry_run):
if not version:
tag = subprocess.run('git describe --tags --abbrev=0 --match v*'.split(),
check=True, capture_output=True, text=True)
@ -30,77 +31,77 @@ def do_release(version, increment):
major, minor, patch = (major, minor, patch+1)
version = f'{major}.{minor}.{patch}'
res = subprocess.run('git status --porcelain --untracked-files=no'.split(),
check=True, capture_output=True, text=True)
if res.stdout.strip():
raise click.ClickException('There are uncommitted changes in this repository.')
if not dry_run:
res = subprocess.run('git status --porcelain --untracked-files=no'.split(),
check=True, capture_output=True, text=True)
if res.stdout.strip():
raise click.ClickException('There are uncommitted changes in this repository.')
print('Cleaning old footprints')
footprint_dir = Path('de.jaseg.kimesh.footprints') / 'footprints'
shutil.rmtree(footprint_dir, ignore_errors=True)
footprint_dir.mkdir()
print('Re-generating footprints')
for n in range(1, 9):
subprocess.run(['python', '-m', 'footprint_generator',
'-w', '0.100,0.120,0.150,0.200,0.250,0.300,0.350,0.400,0.500,0.600,0.700,0.800,1.000,1.200,1.500,1.800',
'-c', '0.100,0.120,0.150,0.200,0.300,0.400,0.500',
'-n', str(n),
str(footprint_dir / f'kimesh_anchors_{n}wire.pretty')
], check=True)
project_root = Path(__file__).parent
res = subprocess.run('git ls-files'.split(), check=True, capture_output=True, text=True)
for path in res.stdout.splitlines():
if re.fullmatch(r'de\.jaseg\.kimesh\.[^/]*-v[.0-9]*\.zip', path.strip()):
if re.fullmatch(r'de\.jaseg\.kicoil\.[^/]*-v[.0-9]*\.zip', path.strip()):
print(f'Removing old release zip {path} from git index.')
subprocess.run(['git', 'rm', path], check=True, capture_output=True)
for pkg_dir in Path('de.jaseg.kimesh.plugin'), Path('de.jaseg.kimesh.footprints'):
# NOTE: metadata.json appears twice. In what I believe is a sub-optimal design choice, the variant in the
# archive is only allowed to contain the current version in its version list without its zip file metadata,
# while the variant in the repository index is supposed to contain all past versions including their zip file
# metadata. AFAICT they are the same otherwise.
meta_path = Path(f'{pkg_dir}-repo-metadata.json')
plugin_sources = project_root / 'kicad-plugin'
pkg_dir = project_root / 'de.jaseg.kicoil'
print(f'Updating metadata file {meta_path}')
ver_dict = {
'version': version,
'status': 'stable',
'kicad_version': '7.99',
}
if pkg_dir.is_dir():
shutil.rmtree(pkg_dir)
# Include just the version metadata in the metadata for the archive
meta_file = json.loads(meta_path.read_text())
meta_file['versions'] = [ver_dict]
(pkg_dir / 'metadata.json').write_text(json.dumps(meta_file, indent=4))
shutil.copytree(plugin_sources, pkg_dir)
shutil.copy(project_root / 'LICENSE', pkg_dir)
zip_fn = Path(shutil.make_archive(f'{pkg_dir.name}-v{version}', 'zip', pkg_dir, '.'))
meta_path = project_root / 'metadata.json'
print(f'Updating metadata file {meta_path}')
ver_dict = {
'version': version,
'status': 'stable',
'kicad_version': '9.00',
}
meta_file = json.loads(meta_path.read_text())
meta_file['versions'] = [ver_dict]
(pkg_dir / 'metadata.json').write_text(json.dumps(meta_file, indent=4))
res = subprocess.run(['uv', 'export', '--no-hashes', '--format', 'requirements-txt'],
check=True, capture_output=True, text=True)
(pkg_dir / 'requirements.txt').write_text(res.stdout)
shutil.copytree(project_root / 'src' / 'kicoil', pkg_dir / 'kicoil')
zip_fn = Path(shutil.make_archive(f'{pkg_dir.name}-v{version}', 'zip', pkg_dir, '.'))
if not dry_run:
print(f'Adding new release zip {zip_fn} to git index.')
subprocess.run(['git', 'add', str(zip_fn)], check=True, capture_output=True)
# Add the zip's metadata to the metadata for the repository
ver_dict['download_sha256'] = hashlib.sha256(zip_fn.read_bytes()).hexdigest()
ver_dict['download_size'] = zip_fn.stat().st_size
ver_dict['download_url'] = f'https://git.jaseg.de/kimesh.git/plain/{zip_fn.name}?h=v{version}'
ver_dict['install_size'] = tree_size(pkg_dir)
# Add the zip's metadata to the metadata for the repository
ver_dict['download_sha256'] = hashlib.sha256(zip_fn.read_bytes()).hexdigest()
ver_dict['download_size'] = zip_fn.stat().st_size
ver_dict['download_url'] = f'https://git.jaseg.de/kimesh.git/plain/{zip_fn.name}?h=v{version}'
ver_dict['install_size'] = tree_size(pkg_dir)
meta_file = json.loads(meta_path.read_text())
meta_file['versions'].append(ver_dict)
meta_path.write_text(json.dumps(meta_file, indent=4))
meta_file = json.loads(meta_path.read_text())
meta_file['versions'].append(ver_dict)
meta_path.write_text(json.dumps(meta_file, indent=4))
if not dry_run:
print(f'Adding updated metadata file {meta_path} to git index')
subprocess.run(['git', 'add', str(meta_path)], check=True, capture_output=True)
print('Create git commit')
subprocess.run(['git', 'commit', '-m', f'Version {version}', '--no-edit'], check=True, capture_output=True)
res = subprocess.run('git rev-parse --short HEAD'.split(), check=True, capture_output=True, text=True)
print(f'Created commit {res.stdout.strip()}')
print(f'Creating and signing version tag v{version}')
subprocess.run(['git',
'-c', 'user.signingkey=E36F75307F0A0EC2D145FF5CED7A208EEEC76F2D',
'-c', 'user.email=python-mpv@jaseg.de',
'tag', '-s', f'v{version}', '-m', f'Version v{version}'],
check=True)
if not dry_run:
print('Create git commit')
subprocess.run(['git', 'commit', '-m', f'Version {version}', '--no-edit'], check=True, capture_output=True)
res = subprocess.run('git rev-parse --short HEAD'.split(), check=True, capture_output=True, text=True)
print(f'Created commit {res.stdout.strip()}')
print(f'Creating and signing version tag v{version}')
subprocess.run(['git',
'-c', 'user.signingkey=E36F75307F0A0EC2D145FF5CED7A208EEEC76F2D',
'-c', 'user.email=python-mpv@jaseg.de',
'tag', '-s', f'v{version}', '-m', f'Version v{version}'],
check=True)
if __name__ == '__main__':
do_release()

View file

@ -5,7 +5,11 @@ description = "Planar Inductor Generator"
readme = "README.rst"
license = "Apache-2.0"
requires-python = ">=3.13"
dependencies = ["click", "gerbonara>=1.6.0"]
dependencies = [
"click",
"gerbonara>=1.6.0",
"kicad-python>=0.5.0",
]
authors = [{ name = "jaseg" }]
maintainers = [
{ name = "Kicoil maintainers", email = "kicoil@jaseg.de" },

View file

@ -122,7 +122,8 @@ class EntryWithPlaceholder(tk.Entry):
class KiCoilGUI:
def __init__(self, root):
def __init__(self, root, kicad_inst=None):
self.kicad_inst = kicad_inst
self.root = root
self.root.title("KiCoil - Planar Inductor Generator")
self.root.geometry("1000x650")
@ -175,8 +176,11 @@ class KiCoilGUI:
ttk.Button(button_frame, text="Show Valid Twists",
command=self.show_valid_twists, width=20).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="Generate and Save",
command=self.generate_footprint, width=20).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="Save Footprint File",
command=self.save_footprint_file, width=20).pack(side=tk.LEFT, padx=5)
if self.kicad_inst:
ttk.Button(button_frame, text="Update Footprint on Board",
command=self.update_board_footprint, width=20).pack(side=tk.LEFT, padx=5)
status_label = ttk.Label(main_frame, text="Output:", font=('Helvetica', 10, 'bold'))
status_label.grid(row=3, column=0, sticky=tk.W, pady=(10, 0))
@ -496,10 +500,10 @@ class KiCoilGUI:
def capture_warnings(self):
"""Context manager to capture kicoil's warnings to the output text widget"""
def show_warning(message, category, filename, lineno, file=None, line=None):
self.output_text.config(state='normal')
self.output_text['state'] = 'normal'
self.output_text.insert(tk.END, f'{message}\n', 'warning')
self.output_text.see(tk.END)
self.output_text.config(state='disabled')
self.output_text['state'] = 'disabled'
self.output_text.update_idletasks()
old_showwarning, warnings.showwarning = warnings.showwarning, show_warning
@ -540,7 +544,7 @@ class KiCoilGUI:
def validate_parameters(self):
"""Validate parameters by creating PlanarInductor instance"""
try:
self.output_text.config(state='normal')
self.output_text['state'] = 'normal'
self.output_text.delete('1.0', tk.END)
with self.capture_warnings():
@ -572,7 +576,7 @@ class KiCoilGUI:
return True
finally:
self.output_text.config(state='disabled')
self.output_text['state'] = 'disabled'
def update_placeholders(self):
if self.current_model is None:
@ -622,20 +626,99 @@ class KiCoilGUI:
def show_valid_twists(self):
"""Show valid twist counts for current number of turns"""
turns = self.turns_var.get()
valid_twists = list(divisors(turns, turns))
self.output_text.config(state='normal')
self.output_text['state'] = 'normal'
self.output_text.delete('1.0', tk.END)
self.output_text.insert('1.0', f'Valid twist counts for {turns} turns:\n')
for d in valid_twists:
self.output_text.insert(tk.END, f' {d}\n')
self.output_text.config(state='disabled')
self.output_text['state'] = 'disabled'
def generate_footprint(self):
"""Generate the KiCad footprint using the validated model"""
def update_board_footprint(self):
if not self.validate_parameters():
messagebox.showerror("Error", "Cannot generate model. Please check the output for warnings or errors.")
return
from kipy.board_types import FootprintInstance, Footprint, Pad, BoardArc, BoardSegment, FootprintAttributes,\
PadStack, PadStackLayer, PadStackType, PadStackShape, DrillProperties, PadType
from kipy.geometry import Vector2
from kipy.common_types import GraphicAttributes, StrokeAttributes
from kipy.util import from_mm
from kipy.util.board_layer import CANONICAL_LAYER_NAMES
from gerbonara.cad.kicad.footprints import Atom
board = self.kicad_inst.get_board()
selected = [item for item in board.get_selection() if isinstance(item, FootprintInstance)]
if not selected:
messagebox.showerror("Error", "No footprint selected. Select one footprint to replace in KiCad's PCB editor.")
return
elif len(selected) > 1:
messagebox.showerror("Error", "More than one footprint selected. Select only the footprint you want to replace.")
return
selected_footprint, = selected
footprint_name = self.footprint_name_entry.get() or None
arc_tolerance = self.arc_tolerance_var.get()
circle_segments = self.circle_segments_var.get()
self.output_text['state'] = 'normal'
self.output_text.insert(tk.END, "Rendering footprint...\n", 'info')
self.output_text.see(tk.END)
model = self.current_model.render_footprint(footprint_name, arc_tolerance, circle_segments)
selected_footprint.attributes.exclude_from_bill_of_materials = True
layer_map = {v: k for k, v in CANONICAL_LAYER_NAMES.items()}
items = []
for line in model.lines:
seg = BoardSegment()
seg.start = Vector2.from_xy(from_mm(line.start.x), from_mm(line.start.y))
seg.end = Vector2.from_xy(from_mm(line.end.x), from_mm(line.end.y))
seg.attributes.stroke.width = from_mm(line.stroke.width)
seg.layer = layer_map[line.layer]
selected_footprint.definition.add_item(seg)
items.append(seg)
for ref in model.arcs:
arc = BoardArc()
arc.start = Vector2.from_xy(from_mm(ref.start.x), from_mm(ref.start.y))
arc.mid = Vector2.from_xy(from_mm(ref.mid.x), from_mm(ref.mid.y))
arc.end = Vector2.from_xy(from_mm(ref.end.x), from_mm(ref.end.y))
arc.attributes.stroke.width = from_mm(ref.stroke.width)
arc.layer = layer_map[ref.layer]
selected_footprint.definition.add_item(arc)
items.append(arc)
for ref in model.pads:
pad = Pad()
pad.number = ref.number
pad.position = Vector2.from_xy(from_mm(ref.at.x), from_mm(ref.at.y))
pad.type = PadType.PT_SMD if ref.type == Atom.smd else PadType.PT_PTH
pad.padstack.type = PadStackType.PST_NORMAL
pad.padstack.layers = [layer_map[name] for name in ref.layers]
layer = pad.padstack.copper_layers[0]
layer.shape = PadStackShape.PSS_CIRCLE
layer.size = Vector2.from_xy(from_mm(ref.size.x), from_mm(ref.size.y))
layer.layer = layer_map[ref.layers[0]] # ? duplicate
if ref.drill:
pad.padstack.drill.diameter = Vector2.from_xy(from_mm(ref.drill.diameter), from_mm(ref.drill.diameter))
selected_footprint.definition.add_item(pad)
items.append(pad)
commit = board.begin_commit()
board.create_items(items)
board.update_items([selected_footprint])
board.push_commit(commit, 'Updated planar coil footprint')
self.output_text.insert(tk.END, "Done.", 'info')
self.output_text['state'] = 'disabled'
self.output_text.see(tk.END)
def save_footprint_file(self):
if not self.validate_parameters():
messagebox.showerror("Error", "Cannot generate model. Please check the output for warnings or errors.")
return
@ -645,7 +728,7 @@ class KiCoilGUI:
arc_tolerance = self.arc_tolerance_var.get()
circle_segments = self.circle_segments_var.get()
self.output_text.config(state='normal')
self.output_text['state'] = 'normal'
self.output_text.insert(tk.END, "Rendering footprint...\n\n", 'info')
footprint = self.current_model.render_footprint(footprint_name, arc_tolerance, circle_segments)
@ -666,7 +749,7 @@ class KiCoilGUI:
except Exception as e:
tb = traceback.format_exc()
self.output_text.config(state='normal')
self.output_text['state'] = 'normal'
self.output_text.insert(tk.END, f"\nError generating footprint:\n{tb}\n", 'error')
self.output_text.see(tk.END)
@ -675,13 +758,13 @@ class KiCoilGUI:
messagebox.showerror("Error", f"Error generating footprint: {e}")
finally:
self.output_text.config(state='disabled')
self.output_text['state'] = 'disabled'
def main():
def main(kicad_inst=None):
from kipy import KiCad
from kipy.errors import ConnectionError
kicad_inst = KiCad()
root = tk.Tk()
app = KiCoilGUI(root)
app = KiCoilGUI(root, kicad_inst)
root.mainloop()
if __name__ == "__main__":
main()

57
uv.lock generated
View file

@ -243,6 +243,19 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
]
[[package]]
name = "kicad-python"
version = "0.5.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "protobuf" },
{ name = "pynng" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/ad/b33939d2e0c099f04875c250564dde79baec09927c5c70a7a101cd612d94/kicad_python-0.5.0.tar.gz", hash = "sha256:9abb6ad87b822b6c63c80543e485e674bddc46080f9706ae3dff7f05d8dc63f9", size = 198708, upload-time = "2025-10-13T15:10:03.665Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ad/ab/b9edb6088ba8263a7f2446f1f3ae088c50bde149d7dc149abca32c4d21d2/kicad_python-0.5.0-py3-none-any.whl", hash = "sha256:fe7adeff9f1c23a76f2ace9468faadcbeef915ce026b187ca35db1cf4faa4451", size = 130154, upload-time = "2025-10-13T15:10:02.695Z" },
]
[[package]]
name = "kicoil"
version = "0.9.0"
@ -250,6 +263,7 @@ source = { editable = "." }
dependencies = [
{ name = "click" },
{ name = "gerbonara" },
{ name = "kicad-python" },
]
[package.dev-dependencies]
@ -262,6 +276,7 @@ gui = [
requires-dist = [
{ name = "click" },
{ name = "gerbonara", specifier = ">=1.6.0" },
{ name = "kicad-python", specifier = ">=0.5.0" },
]
[package.metadata.requires-dev]
@ -389,6 +404,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa", size = 8946, upload-time = "2021-06-27T10:15:03.856Z" },
]
[[package]]
name = "protobuf"
version = "5.29.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" },
{ url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" },
{ url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" },
{ url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" },
{ url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" },
{ url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" },
]
[[package]]
name = "pycparser"
version = "2.23"
@ -398,6 +427,25 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
]
[[package]]
name = "pynng"
version = "0.8.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cffi" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d4/8c/23141a4b94fdb69c72fe54734a5da192ecbaf5c4965ba6d3a753e6a8ac34/pynng-0.8.1.tar.gz", hash = "sha256:60165f34bdf501885e0acceaeed79bc35a57f3ca3c913cb38c14919b9bd3656f", size = 6364925, upload-time = "2025-01-16T03:42:32.848Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0d/fd/b6b43259bf87c7640824310c930761ea814eb4b726f2814ef847ad80d96d/pynng-0.8.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1013dc1773e8a4cee633a8516977d59c17711b56b0df9d6c174d8ac722b19d9", size = 1089913, upload-time = "2025-01-16T03:41:01.543Z" },
{ url = "https://files.pythonhosted.org/packages/44/71/134faf3a6689898167c0b8a55b8a55069521bc79ae6eed1657b075545481/pynng-0.8.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a89b5d3f9801913a22c85cf320efdffc1a2eda925939a0e1a6edc0e194eab27", size = 727669, upload-time = "2025-01-16T03:41:04.936Z" },
{ url = "https://files.pythonhosted.org/packages/72/3d/2d77349fa87671d31c5c57ea44365311338b0a8d984e8b095add62f18fda/pynng-0.8.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2f0a7fdd96c99eaf1a1fce755a6eb39e0ca1cf46cf81c01abe593adabc53b45", size = 938072, upload-time = "2025-01-16T03:41:09.685Z" },
{ url = "https://files.pythonhosted.org/packages/04/91/580382d32fe90dd3cc0310358d449991070091b78a8f97df3f8e4b3d5fee/pynng-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cbda575215e854a241ae837aac613e88d197b0489ef61f4a42f2e9dd793f01", size = 736250, upload-time = "2025-01-16T03:41:11.304Z" },
{ url = "https://files.pythonhosted.org/packages/b6/db/9bf6a8158187aa344c306c6037ff20d134132d83596dcbb8537faaad610d/pynng-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3f635d6361f9ad81d16ba794a5a9b3aa47ed92a7709b88396523676cb6bddb1f", size = 941514, upload-time = "2025-01-16T03:41:13.156Z" },
{ url = "https://files.pythonhosted.org/packages/26/f3/9a7676e3d115834a5acf674590bb32e61f9caa5b8f0971628fc562670d35/pynng-0.8.1-cp313-cp313-win32.whl", hash = "sha256:6d5c51249ca221f0c4e27b13269a230b19fc5e10a60cbfa7a8109995b22e861e", size = 370575, upload-time = "2025-01-16T03:41:15.998Z" },
{ url = "https://files.pythonhosted.org/packages/ff/0e/11d76f7aeb733e966024eb6b6adf73280d2c600f8fa8bdb6ea34d33e9a19/pynng-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:1f9c52bca0d063843178d6f43a302e0e2d6fbe20272de5b3c37f4873c3d55a42", size = 450453, upload-time = "2025-01-16T03:41:17.604Z" },
]
[[package]]
name = "quart"
version = "0.20.0"
@ -434,6 +482,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/3f/50/0a9e7e7afe7339bd5e36911f0ceb15fed51945836ed803ae5afd661057fd/rtree-1.4.1-py3-none-win_arm64.whl", hash = "sha256:3d46f55729b28138e897ffef32f7ce93ac335cb67f9120125ad3742a220800f0", size = 355253, upload-time = "2025-08-13T19:32:00.296Z" },
]
[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
]
[[package]]
name = "tinycss2"
version = "1.5.1"