kicad/scripting/plugins/BomGeneration/jlcparts.py

100 lines
3.9 KiB
Python
Raw Blame History

import argparse
import numpy as np
import pandas as pd
import re
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
parser = argparse.ArgumentParser()
parser.add_argument("input", nargs="?", default=None)
args = parser.parse_args()
def mlcc_code2specs(code):
specs = {}
code = code.lower()
if code in ["c0g", "np0"]:
# type 1
specs["temperature_min"] = -55
specs["temperature_max"] = +125
specs["tolerance"] = 0
else:
# type 2
specs["temperature_min"] = {"x": -55, "y": -30, "z": +10}[code[0]]
specs["temperature_max"] = {2: +45, 4: +65, 5: +85, 6: +105, 7: +125}[int(code[1])]
specs["tolerance"] = {"d":0.033, "e":0.047, "f":0.075, "p":0.10, "r":0.15, "s":0.22, "t":0.33, "u":0.56, "v":0.82}[code[2]]
footprints = {
"0402": (2, ["0402", "R0402", "C0402"]),
"0603": (2, ["0603", "R0603", "C0603"]),
"0805": (2, ["0805", "R0805", "C0805"]),
"1206": (2, ["1206", "R1206", "C1206"]),
"1210": (2, ["1210", "R1210", "C1210"]),
"1218": (2, ["1218", "R1218", "C1218"]),
"2512": (2, ["2512", "R2512", "C2512"]),
}
# TODO: remove hardcoded csv
args.input = "/home/brendan/Documents/tempsync/projects/0034_UniversalController/jlcparts.csv"
if args.input:
parts_csv = pd.read_csv(args.input, encoding_errors="replace", delimiter=",", index_col=False)
else:
raise NotImplementedError()
logger.info("Parsing JLCPCB stock...")
stock = parts_csv[parts_csv["Stock"]>0]
# NOTES:
# - if something has tolerance specified as absolute, "Value" may be wrong but "Tolerance" will be NA so it will be dropped
# resistors
resistors = stock[stock["First Category"] == "Resistors"]
resistors.loc[:, "Value"] = resistors["Description"].str.extract(r"(\d+(\.\d+)?)<29><>").astype(float).iloc[:,0]
resistors.loc[:, "Tolerance"] = resistors["Description"].str.extract(r"(\d+)%").astype(float) / 100
resistors.loc[:, "TempCoef"] = resistors["Description"].str.extract(r"(\d+)ppm/<2F><>").astype(float) / 1e6
power_frac = resistors["Description"].str.extract(r"(\d+)/(\d+)W").astype(float)
power_frac = power_frac.iloc[:,0] / power_frac.iloc[:,1]
power_dec = resistors["Description"].str.extract(r"(\d+(\.\d+))W").astype(float).iloc[:,0]
power = power_frac.add(power_dec, fill_value=0)
power[power_frac.notnull() & power_dec.notnull()] = pd.NA
resistors.loc[:, "Power"] = power
resistors.loc[:, "Footprint"] = pd.NA
for fp, (pins, name) in footprints.items():
matches = False
for n in name:
matches = matches | (resistors["Package"] == n)
matches = matches & (resistors["Solder Joint"] == pins)
resistors["Footprint"][matches] = fp
# resistors.drop("Package", inplace=True)
resistors.dropna(inplace=True)
# capacitors
capacitors = stock[stock["First Category"] == "Capacitors"]
value = capacitors["Description"].str.extract(r"(\d+(\.\d+)?)([pnum]?)F")
value = value.iloc[:,0].astype(float) * value.iloc[:,2].replace(["p", "n", "u", "m", ""], [1e-12, 1e-9, 1e-6, 1e-3, 1]).astype(float)
capacitors.loc[:, "Value"] = value
capacitors.loc[:, "Tolerance"] = capacitors["Description"].str.extract(r"(\d+)%").astype(float) / 100
capacitors.loc[:, "Voltage"] = capacitors["Description"].str.extract(r"(\d+(\.\d+)?)V").astype(float).iloc[:,0]
# TODO: "MLCC"/"Tantalum"
code_np0 = capacitors["Description"].str.contains(r"NP0")
code_t1 = capacitors["Description"].str.extract(r"([CBLAMPRSTVU][01234678][GHJKLMN])")
code_t2 = capacitors["Description"].str.extract(r"([XYZ][24567][DEFPRSTUV])")
code = code_t1
code[code_t2.notnull()] = code_t2
code[code_np0] = "C0G"
capacitors["Code"] = code
capacitors["Footprint"] = pd.NA
for fp, (pins, name) in footprints.items():
matches = False
for n in name:
matches = matches | (capacitors["Package"] == n)
matches = matches & (capacitors["Solder Joint"] == pins)
capacitors["Footprint"][matches] = fp
# capacitors.drop("Package", inplace=True)
capacitors.dropna(inplace=True)
pass