diff --git a/generate_jst.py b/generate_jst.py new file mode 100644 index 0000000..f10531e --- /dev/null +++ b/generate_jst.py @@ -0,0 +1,148 @@ +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" / "3dshapes" / 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, 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 / "3dshapes" / 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(lib) + 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()