kicad/generate_jst.py

149 lines
5.0 KiB
Python

import time
import zipfile
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Literal, Optional, Union
import numpy as np
import regex as re
from selenium import webdriver
from selenium.webdriver.support.select import By
from fp_generator import INCH, Footprint
dir_ = Path(__file__).parent
PARTS = [
# JST-SH, Right angle
*[f"SM{i:02d}B-SRSS-TB" for i in range(2, 16)],
# JST-SH, Vertical
# *[f"BM{i:02d}B-SRSS-TB" for i in range(2, 16)],
]
def round2grid(val: float, direction: Optional[Literal["up", "down"]] = None, grid: float = 0.005 * INCH):
if direction == "up":
val = val + grid / 2
elif direction == "down":
val = val - grid / 2
return np.round(val / grid) * grid
def download_step(part: Union[str, int], headless: bool = True) -> None:
print(part)
with TemporaryDirectory(prefix=str(dir_ / "tmp") + "/") as tmp:
tmp = Path(tmp)
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option(
"prefs",
{"download.default_directory": str(tmp)},
)
if headless:
chrome_options.add_argument("--headless")
with webdriver.Chrome(
options=chrome_options,
) as browser:
browser.get(
f"https://www.jst-mfg.com/product/index.php?type=10&series=231&doc=2&filename={part.upper()}.zip"
)
browser.implicitly_wait(10)
browser.find_element(by=By.ID, value="company").send_keys("N/A")
browser.find_element(by=By.ID, value="section").send_keys("N/A")
browser.find_element(by=By.ID, value="name").send_keys("Brendan Haines")
browser.find_element(by=By.ID, value="address").send_keys("7415 Spy Glass Ct")
browser.find_element(by=By.ID, value="tel").send_keys("(505) 738-6174")
browser.find_element(by=By.ID, value="email").send_keys("brendan.haines@gmail.com")
# browser.find_element(by=By.ID, value="url").send_keys("")
browser.find_element(by=By.XPATH, value="//input[@type='button' and @value='I agree']").click()
# wait for download to finish
while len(list((Path(tmp).glob("*.zip")))) == 0:
time.sleep(0.1)
# print(list((Path(tmp).glob("*.zip"))))
# unzip
with zipfile.ZipFile(tmp / f"{part.upper()}.zip") as zip:
zip.extractall(path=tmp)
# move
(Path(tmp) / f"{part.upper()}.STEP").rename(dir_ / "jst.pretty" / "step" / f"{part.upper()}.stp")
def footprint(part: str, lib: Optional[Union[Path, str]] = None):
print(part)
if lib is None:
lib = dir_ / "jst.pretty"
lib = Path(lib)
if part.startswith("SM"):
# Right angle
match = re.match(r"SM(\d\d)B-SRSS-TB", part)
pins = int(match[1])
fp = Footprint(part, lib=lib, description=f"connector, JST-SH, 1x{pins:02f}, RA")
fp.add_text("reference", "REF**", (5.55 + (0.025 + 0.005) * INCH), 0, rotation=90, layer="F.SilkS")
fp.add_text("value", "VAL**", 4 * 0.025 * INCH, 0, rotation=90, layer="F.Fab")
fp.add_text("user", r"${REFERENCE}**", 2 * 0.025 * INCH, 0, rotation=90, layer="F.Fab")
a, b = {
2: (1, 4),
3: (2, 5),
4: (3, 6),
5: (4, 7),
6: (5, 8),
7: (6, 9),
8: (7, 10),
9: (8, 11),
10: (9, 12),
11: (10, 13),
12: (11, 14),
13: (12, 15),
14: (13, 16),
15: (14, 17),
20: (19, 22),
}[pins]
# fp.add_line((0.05 * INCH, -0.05 * INCH), (0.05 * INCH, 0.05 * INCH), layer="F.SilkS")
for pad in range(pins):
fp.add_pad(
pad + 1,
4 + (5.55 - 4) / 2,
-1.0 * (pins - 1) / 2 + 1.0 * pad,
size=(5.55 - 4, 0.6),
shape="rect",
)
# mechanical holes
for s in [1, -1]:
fp.add_pad(0, 1.8 / 2, s * (1.0 * (pins - 1) / 2 + 0.7 + 1.2 / 2), size=(1.8, 1.2), shape="rect")
fp.add_model(
lib / "step" / f"{part}.stp",
(4, 0, -0.3),
rotate=(-90, 0, 90),
)
fp.add_rect((0.2, -b / 2), (0.2 + 4.25, b / 2), layer="F.Fab")
for s in [1, -1]:
fp.add_line(
(0.190 * INCH, s * round2grid((a + 0.6) / 2 + 0.010 * INCH, "up")),
(0.190 * INCH, s * round2grid(b / 2 + 0.010 * INCH, "up")),
layer="F.SilkS",
)
fp.add_line(
(0.190 * INCH, s * round2grid(b / 2 + 0.010 * INCH, "up")),
(round2grid(1.8 + 0.010 * INCH), s * round2grid(b / 2 + 0.010 * INCH, "up")),
layer="F.SilkS",
)
fp.write()
else:
raise NotImplementedError
if __name__ == "__main__":
from multiprocessing import Pool
pool = Pool(10)
# pool.map(download_step, PARTS)
for part in PARTS:
footprint(part)
pool.close()