818 lines
31 KiB
Python
818 lines
31 KiB
Python
import requests
|
|
import os
|
|
import json
|
|
import re
|
|
import shutil
|
|
import pandas as pd
|
|
from autoLibrarySymbols import * # librarySymbols.py
|
|
from handmadeLibrarySymbols import * # handmadeLibrarySymbols.py
|
|
from packageTools import * # packageTools.py
|
|
from datetime import datetime
|
|
from datetime import timezone
|
|
|
|
|
|
def download_file(url, filename):
|
|
"""
|
|
Downloads a file from the specified URL and saves it to the given filename.
|
|
If the file already exists, it will be deleted before downloading the new file.
|
|
|
|
:param url: The base URL of the file to download.
|
|
:param filename: The local filename to save the downloaded file.
|
|
"""
|
|
try:
|
|
# Check if the file already exists and delete it if it does
|
|
if os.path.exists(filename):
|
|
os.remove(filename)
|
|
print(f"Deleted existing file: {filename}")
|
|
|
|
# Construct the full URL for the file
|
|
full_url = f"{url}/{filename}"
|
|
|
|
# Send a GET request to download the file
|
|
response = requests.get(full_url, stream=True)
|
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
|
|
# Write the content to a file in binary mode
|
|
with open(filename, "wb") as f:
|
|
for chunk in response.iter_content(chunk_size=None):
|
|
f.write(chunk)
|
|
|
|
print(f"Downloaded {full_url} to {filename}")
|
|
except requests.RequestException as e:
|
|
print(f"Download failed for {full_url}: {e}")
|
|
|
|
|
|
def extract_capacitor_value(description, lcsc_id):
|
|
"""
|
|
Extracts the capacitor value from the given description based on the LCSC ID.
|
|
If the LCSC ID matches a known value, it returns the corresponding capacitance.
|
|
Otherwise, it uses a regex pattern to extract the capacitance from the description.
|
|
|
|
:param description: The description of the capacitor.
|
|
:param lcsc_id: The LCSC ID of the capacitor.
|
|
:return: The extracted capacitance value as a string, or None if no value is found.
|
|
"""
|
|
# Define known LCSC IDs and their corresponding capacitance values
|
|
known_values = {30274: "6pF", 3013473: "100nF", 3008298: "4.7nF"}
|
|
|
|
# Check if the LCSC ID matches a known value
|
|
if lcsc_id in known_values:
|
|
return known_values[lcsc_id]
|
|
|
|
# Define a regex pattern to match capacitance values
|
|
pattern = r"(\d+(?:\.\d+)?(?:[pnu]?)(?:f|farad))" # matches numbers followed by F, f, Farad, farad, pF, pf, nF, nf, uF, uf
|
|
|
|
# Search for the pattern in the description
|
|
match = re.search(pattern, description, re.IGNORECASE)
|
|
if match:
|
|
return match.group(0)
|
|
else:
|
|
print(f"Error: No value found for https://jlcpcb.com/partdetail/C{lcsc_id} ({description})")
|
|
return None
|
|
|
|
|
|
def extract_resistance_value(description, lcsc_id):
|
|
"""
|
|
Extracts the resistance value from the given description based on the LCSC ID.
|
|
If the LCSC ID matches a known value, it returns the corresponding resistance.
|
|
Otherwise, it uses a regex pattern to extract the resistance from the description.
|
|
|
|
:param description: The description of the resistor.
|
|
:param lcsc_id: The LCSC ID of the resistor.
|
|
:return: The extracted resistance value as a string, or None if no value is found.
|
|
"""
|
|
# Define known LCSC IDs and their corresponding resistance values
|
|
known_values = {22818: "16kΩ"}
|
|
|
|
# Check if the LCSC ID matches a known value
|
|
if lcsc_id in known_values:
|
|
return known_values[lcsc_id]
|
|
|
|
# Define a regex pattern to match resistance values
|
|
pattern = r"(\d+(?:\.\d+)?(?:[kMGT]?)(?:Ω|ohm))" # matches numbers followed by Ω, ohm, Ohm, or OHM
|
|
|
|
# Search for the pattern in the description
|
|
match = re.search(pattern, description, re.IGNORECASE)
|
|
if match:
|
|
return match.group(0)
|
|
else:
|
|
print(f"Error: No value found for https://jlcpcb.com/partdetail/C{lcsc_id} ({description})")
|
|
return None
|
|
|
|
|
|
def extract_diode_type(description, pins, lcsc_id):
|
|
if lcsc_id == 2990493:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2990473:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2990416:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2990414:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2990261:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2990124:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 3019524:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 1323289:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 3001945:
|
|
return "TVS-Uni"
|
|
if lcsc_id == 2833277:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2975471:
|
|
return "TVS-Uni"
|
|
if lcsc_id == 78395:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2925443:
|
|
return "TVS-Uni"
|
|
if lcsc_id == 2936988:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2925441:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 2925451:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 20617908:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 20617910:
|
|
return "TVS-Bi"
|
|
if lcsc_id == 22466368:
|
|
return "Schottky13"
|
|
if lcsc_id == 22466371:
|
|
return "Schottky13"
|
|
if lcsc_id == 28646292:
|
|
return "Schottky"
|
|
if lcsc_id == 28646296:
|
|
return "Schottky"
|
|
if lcsc_id == 28646302:
|
|
return "Schottky"
|
|
if lcsc_id == 28646299:
|
|
return "Schottky"
|
|
if lcsc_id == 28646283:
|
|
return "Schottky"
|
|
if lcsc_id == 41411783:
|
|
return "TVS-Uni"
|
|
if lcsc_id == 41376087:
|
|
return "TVS-Uni"
|
|
|
|
diode_types = {
|
|
"Schottky": {"pins": 2, "type": "Schottky"},
|
|
"Recovery": {"pins": 2, "type": "Recovery"},
|
|
"General": {"pins": 2, "type": "General"},
|
|
"Switching": {"pins": 2, "type": "Switching"},
|
|
"Zener": {"pins": 2, "type": "Zener"},
|
|
"Bidirectional": {"pins": 2, "type": "TVS-Bi"},
|
|
"Unidirectional": {"pins": 2, "type": "TVS-Uni"},
|
|
"TVS": {"pins": 2, "type": "TVS-Uni"},
|
|
}
|
|
for keyword, diode_info in diode_types.items():
|
|
if keyword.casefold() in description.casefold():
|
|
if diode_info["pins"] == pins:
|
|
return diode_info["type"]
|
|
elif keyword == "Zener" and pins == 3:
|
|
return "Zener13"
|
|
else:
|
|
return None
|
|
return None
|
|
|
|
|
|
def extract_transistor_type(description, pins, footprint, lcsc_id):
|
|
if lcsc_id == 484513:
|
|
return "NMOS"
|
|
if lcsc_id == 396043:
|
|
return "NMOS"
|
|
if lcsc_id == 916398:
|
|
return "NMOS"
|
|
if lcsc_id == 296127:
|
|
return None
|
|
if lcsc_id == 41375139:
|
|
return "PNPC2"
|
|
if lcsc_id == 28646267:
|
|
return "NPNC2"
|
|
if lcsc_id == 41375135:
|
|
pins = 3
|
|
if lcsc_id == 41375119:
|
|
pins = 3
|
|
|
|
transistor_types = {
|
|
"PNP": {"pins": 3, "type": "PNP"},
|
|
"NPN": {"pins": 3, "type": "NPN"},
|
|
"NChannel": {"pins": 3, "type": "NMOS"},
|
|
"PChannel": {"pins": 3, "type": "PMOS"},
|
|
"N-Channel": {"pins": 3, "type": "NMOS"},
|
|
"P-Channel": {"pins": 3, "type": "PMOS"},
|
|
}
|
|
for keyword, transistor_info in transistor_types.items():
|
|
if keyword.casefold() in description.casefold():
|
|
if transistor_info["pins"] == pins:
|
|
if footprint == "SOT-89":
|
|
return f"{transistor_info["type"]}C2" # Collector/ and Emitter pin number is flipped
|
|
else:
|
|
return transistor_info["type"]
|
|
else:
|
|
# print(f"Error: Number of pins ({pins}) does not match expected ({transistor_info['pins']}) for https://jlcpcb.com/partdetail/C{lcsc_id} ({description})")
|
|
return None
|
|
# print(f"Error: No transistor type found for https://jlcpcb.com/partdetail/C{lcsc_id} ({description})")
|
|
return None
|
|
|
|
|
|
def extract_LED_value(description, lcsc_):
|
|
if lcsc == 2985996:
|
|
return "Red", "LED"
|
|
elif lcsc == 34499:
|
|
return "White", "LED"
|
|
elif lcsc == 2986058:
|
|
return "Blue", "LED"
|
|
elif lcsc == 2986059:
|
|
return "Green", "LED"
|
|
|
|
color_pattern = r"(Red|Green|Blue|Yellow|White|Emerald)"
|
|
|
|
color_match = re.search(color_pattern, description, re.IGNORECASE)
|
|
|
|
if color_match:
|
|
color = color_match.group(0).replace("Emerald", "Green")
|
|
return color, "LED"
|
|
else:
|
|
print(f"Error: No LED value extracted for https://jlcpcb.com/partdetail/C{lcsc} ({description})")
|
|
return None, None
|
|
|
|
|
|
def extract_inductor_type_value(description, joints, lcsc):
|
|
current = None
|
|
if lcsc == 2827387:
|
|
current = "300mA"
|
|
if lcsc == 2827415:
|
|
current = "900mA"
|
|
if lcsc == 3007708:
|
|
current = "410mA"
|
|
if lcsc == 2844914:
|
|
current = "305mA"
|
|
if lcsc == 2827354:
|
|
current = "5.5A"
|
|
if lcsc == 2827458:
|
|
current = "400mA"
|
|
if lcsc == 2835403:
|
|
return "120nH,80mA", "Inductor"
|
|
if lcsc == 27143:
|
|
return "15nH,300mA", "Inductor"
|
|
|
|
# Define patterns to match inductance values
|
|
inductance_patterns = [
|
|
r"\b(\d+\.\d+[u|m|n]H)\b", # e.g. 10.5uH, 10.5mH, 10.5nH
|
|
r"\b(\d+[u|m|n]H)\b", # e.g. 10uH, 10mH, 10nH
|
|
]
|
|
|
|
# Define patterns to match current values
|
|
current_patterns = [
|
|
r"(\d+(\.\d+)?)A", # e.g. 1A, 2A, 4.95A
|
|
r"(\d+)mA", # e.g. 100mA, 2000mA
|
|
]
|
|
|
|
# Iterate over patterns and search for matches
|
|
for pattern in inductance_patterns:
|
|
inductance_match = re.search(pattern, description, re.IGNORECASE)
|
|
if inductance_match:
|
|
# Extract inductance value
|
|
inductance = inductance_match.group(1)
|
|
|
|
# Extract current value
|
|
if current == None:
|
|
for current_pattern in current_patterns:
|
|
current_match = re.search(current_pattern, description, re.IGNORECASE)
|
|
if current_match:
|
|
current = current_match.group(1)
|
|
if "mA" in current_pattern:
|
|
current += "mA"
|
|
else:
|
|
current += "A"
|
|
break
|
|
else:
|
|
current = ""
|
|
print(
|
|
f"Error: No current value extracted for https://jlcpcb.com/partdetail/C{lcsc} ({description})"
|
|
)
|
|
|
|
# Return inductance and current values
|
|
return f"{inductance},{current}", "Inductor"
|
|
|
|
if "Ferrite" in description:
|
|
return "", "Ferrite"
|
|
|
|
# If no match is found, print an error message and return None
|
|
print(f"Error: No inductance value extracted for https://jlcpcb.com/partdetail/C{lcsc} ({description})")
|
|
return None, None
|
|
|
|
|
|
def extract_variable_resistor_type_value(description, lcsc):
|
|
# NTC Thermistors
|
|
if lcsc == 2991699:
|
|
return "NTC", "47kΩ,4050"
|
|
if "NTC" in description:
|
|
pattern = r"(\d+(?:\.\d+)?Ω)" # matches numbers followed by Ω
|
|
match = re.search(pattern, description)
|
|
if match:
|
|
return "NTC", match.group(0)
|
|
else:
|
|
print(f"Error: Unknown resistance for https://jlcpcb.com/partdetail/C{lcsc} ({description})")
|
|
return None, None
|
|
|
|
# Varistors (MOV)
|
|
elif "Varistors" in description:
|
|
return "MOV", ""
|
|
|
|
# Fuses
|
|
elif "Fuse" or "fuse" in description:
|
|
if lcsc == 2924957:
|
|
value = "1.5A"
|
|
elif lcsc == 2838983:
|
|
value = "1.5A"
|
|
else:
|
|
value = ""
|
|
if "Resettable" in description:
|
|
return "Fuse,Resettable", value
|
|
else:
|
|
return "Fuse", value
|
|
|
|
# Unknown
|
|
else:
|
|
print(f"Error: Unknown type for https://jlcpcb.com/partdetail/C{lcsc} ({description})")
|
|
return None, None
|
|
|
|
|
|
def extract_capacitor_voltage(description, lcsc):
|
|
voltage_pattern = r"\b(\d+(?:\.\d+)?)(V|kV)\b"
|
|
voltage_match = re.search(voltage_pattern, description, re.IGNORECASE)
|
|
|
|
if voltage_match:
|
|
return voltage_match.group(0)
|
|
else:
|
|
return None
|
|
|
|
|
|
def get_basic_or_prefered_type(df, index):
|
|
if df.loc[index, "basic"] > 0:
|
|
return "Basic Component"
|
|
elif df.loc[index, "preferred"] > 0:
|
|
return "Preferred Component"
|
|
else:
|
|
print("extended component found")
|
|
return "Extended Component"
|
|
|
|
|
|
def generate_kicad_symbol_libs(symbols):
|
|
for lib_name, symbol_list in symbols.items():
|
|
lib_content = "(kicad_symbol_lib\n"
|
|
lib_content += "\t(version 20231120)\n"
|
|
lib_content += '\t(generator "CDFER")\n'
|
|
lib_content += '\t(generator_version "8.0")\n'
|
|
for symbol in symbol_list:
|
|
lib_content += symbol + "\n"
|
|
lib_content += ")\n"
|
|
|
|
lib_content = lib_content.replace("℃", "°C")
|
|
|
|
library_filename = os.path.join("symbols", f"JLCPCB-{lib_name}.kicad_sym")
|
|
|
|
with open(library_filename, "w", encoding="utf-8") as f: # TODO switch with OS.join
|
|
f.write(lib_content)
|
|
|
|
|
|
def check_models():
|
|
exempt_footprints = [
|
|
"Hole, 3mm",
|
|
"Hole_Tooling_JLCPCB",
|
|
"MouseBites, Cosmetic, JLCPCB, 1.6mm",
|
|
"MouseBites, Mechanical, JLCPCB, 1.6mm",
|
|
"Part_Num_JLCPCB",
|
|
]
|
|
|
|
footprints_folder_path = os.path.join("footprints", "JLCPCB.pretty")
|
|
models_folder_path = os.path.join("3dmodels", "JLCPCB.3dshapes")
|
|
archived_models_folder_path = os.path.join("Archived-Symbols-Footprints", "JLCPCB-Kicad-Footprints", "3dModels")
|
|
|
|
footprint_names = [
|
|
os.path.splitext(filename)[0]
|
|
for filename in os.listdir(footprints_folder_path)
|
|
if filename.endswith(".kicad_mod")
|
|
]
|
|
archived_model_names = [
|
|
os.path.splitext(filename)[0]
|
|
for filename in os.listdir(archived_models_folder_path)
|
|
if filename.endswith(".step")
|
|
]
|
|
model_names = [
|
|
os.path.splitext(filename)[0] for filename in os.listdir(models_folder_path) if filename.endswith(".step")
|
|
]
|
|
|
|
model_names_used = []
|
|
|
|
for footprint_name in footprint_names:
|
|
footprint_file_path = os.path.join(footprints_folder_path, f"{footprint_name}.kicad_mod")
|
|
|
|
with open(footprint_file_path, "r", encoding="utf-8") as file:
|
|
content = file.read()
|
|
match = re.search(r'\(model "([^"]+)"', content)
|
|
|
|
if match:
|
|
model_path = match.group(1)
|
|
model = re.search(
|
|
r'/3dmodels/com_github_CDFER_JLCPCB-Kicad-Library/JLCPCB.3dshapes/([^"]+).step', model_path
|
|
)
|
|
if model:
|
|
model = model.group(1)
|
|
if model not in model_names:
|
|
if model in archived_model_names:
|
|
post_move_file_path = os.path.join(models_folder_path, f"{model}.step")
|
|
pre_move_file_path = os.path.join(archived_models_folder_path, f"{model}.step")
|
|
shutil.move(pre_move_file_path, post_move_file_path)
|
|
archived_model_names.remove(model)
|
|
print(f"Un-archived needed model: {model}")
|
|
else:
|
|
print(f"Missing 3D Model for Footprint: {footprint_name} ({model_path})")
|
|
else:
|
|
model_names_used.append(model)
|
|
else:
|
|
print(f"Incorrect Model path for Footprint: {footprint_name} ({model_path})")
|
|
elif footprint_name not in exempt_footprints:
|
|
print(f"Empty Model Field for Footprint: {footprint_name}")
|
|
|
|
for model in model_names:
|
|
if model not in model_names_used:
|
|
pre_move_file_path = os.path.join(models_folder_path, f"{model}.step")
|
|
post_move_file_path = os.path.join(archived_models_folder_path, f"{model}.step")
|
|
shutil.move(pre_move_file_path, post_move_file_path)
|
|
print(f"Archived unused model: {model}")
|
|
|
|
|
|
def check_footprints():
|
|
symbols_folder_path = "symbols"
|
|
footprints_folder_path = os.path.join("footprints", "JLCPCB.pretty")
|
|
archived_footprints_folder_path = os.path.join("Archived-Symbols-Footprints", "JLCPCB-Kicad-Footprints")
|
|
|
|
archived_footprint_names = [
|
|
os.path.splitext(filename)[0]
|
|
for filename in os.listdir(archived_footprints_folder_path)
|
|
if filename.endswith(".kicad_mod")
|
|
]
|
|
footprint_names = [
|
|
os.path.splitext(filename)[0]
|
|
for filename in os.listdir(footprints_folder_path)
|
|
if filename.endswith(".kicad_mod")
|
|
]
|
|
footprint_names_used = []
|
|
|
|
for symbol_lib_filename in os.listdir(symbols_folder_path):
|
|
footprint_file_path = os.path.join(symbols_folder_path, symbol_lib_filename)
|
|
|
|
if os.path.isfile(footprint_file_path) and symbol_lib_filename.endswith(".kicad_sym"):
|
|
with open(footprint_file_path, "r", encoding="utf-8") as file:
|
|
symbol_name = None
|
|
footprint_name = None
|
|
|
|
for line in file:
|
|
# Search for symbol name
|
|
match = re.search(r'\(symbol "([^"]+)"', line)
|
|
if match:
|
|
symbol_name = match.group(1)
|
|
footprint_name = None
|
|
|
|
# Search for footprint
|
|
match = re.search(r'\(property "Footprint" "([^"]+)"', line)
|
|
if match:
|
|
footprint_name = match.group(1)
|
|
footprint_lib_match = re.search(r'PCM_JLCPCB:([^"]+)', footprint_name)
|
|
if footprint_lib_match:
|
|
footprint_name = footprint_lib_match.group(1)
|
|
if footprint_name not in footprint_names:
|
|
if footprint_name in archived_footprint_names:
|
|
post_move_file_path = os.path.join(
|
|
footprints_folder_path, f"{footprint_name}.kicad_mod"
|
|
)
|
|
pre_move_file_path = os.path.join(
|
|
archived_footprints_folder_path, f"{footprint_name}.kicad_mod"
|
|
)
|
|
shutil.move(pre_move_file_path, post_move_file_path)
|
|
archived_footprint_names.remove(footprint_name)
|
|
print(f"Un-archived needed footprint: {footprint_name}")
|
|
else:
|
|
print(
|
|
f"Missing Footprint For Symbol: {symbol_name} -> {footprint_name} ({footprint_file_path})"
|
|
)
|
|
else:
|
|
footprint_names_used.append(footprint_name)
|
|
else:
|
|
print(
|
|
f"Incorrect Symbol Footprint Library For Symbol: {symbol_name} -> {footprint_name} ({footprint_file_path})"
|
|
)
|
|
|
|
for footprint in footprint_names:
|
|
if footprint not in footprint_names_used:
|
|
pre_move_file_path = os.path.join(footprints_folder_path, f"{footprint}.kicad_mod")
|
|
post_move_file_path = os.path.join(archived_footprints_folder_path, f"{footprint}.kicad_mod")
|
|
shutil.move(pre_move_file_path, post_move_file_path)
|
|
print(f"Archived unused footprint: {footprint}")
|
|
|
|
|
|
# Download the latest basic/preferred csv file
|
|
download_file("https://cdfer.github.io/jlcpcb-parts-database", "jlcpcb-components-basic-preferred.csv")
|
|
|
|
df = pd.read_csv("jlcpcb-components-basic-preferred.csv")
|
|
|
|
footprints_dir = "3dmodels/JLCPCB.3dshapes"
|
|
footprints_lookup = {os.path.splitext(file)[0] for file in os.listdir(footprints_dir)}
|
|
|
|
symbols = {
|
|
"Resistors": [],
|
|
"Capacitors": [],
|
|
"Diodes": [],
|
|
"Transistors": [],
|
|
"Inductors": [],
|
|
"Variable-Resistors": [],
|
|
}
|
|
smt_joint_cost = 0.0017
|
|
hand_solder_joint_cost = 0.0173
|
|
|
|
componentList = []
|
|
names_lookup = []
|
|
|
|
for index in range(0, len(df)):
|
|
# lcsc,category_id,category,subcategory,mfr,package,joints,manufacturer,basic,preferred,description,datasheet,stock,last_on_stock,price,extra,Assembly Process,Min Order Qty,Attrition Qty
|
|
lcsc = int(df.loc[index, "lcsc"])
|
|
category = f'{df.loc[index,"category"]},{df.loc[index,"subcategory"]}'
|
|
manufacturer = str(df.loc[index, "manufacturer"])
|
|
manufacturerPartID = df.loc[index, "mfr"]
|
|
footprint_name = str(df.loc[index, "package"])
|
|
footprint_name = footprint_name.replace(
|
|
"插件", "Plugin"
|
|
) # Some through-hole parts use the prefix Plugin or the chinese equivalent
|
|
description = str(df.loc[index, "description"])
|
|
description = description.replace(" ", " ") # Gets rid of double spaces
|
|
joints = int(df.loc[index, "joints"])
|
|
stock = int(df.loc[index, "stock"])
|
|
assembly_process = df.loc[index, "Assembly Process"]
|
|
min_order_qty = int(df.loc[index, "Min Order Qty"])
|
|
attrition_qty = int(df.loc[index, "Attrition Qty"])
|
|
units = 1
|
|
secondary_mode = ""
|
|
subcategory = str(df.loc[index, "subcategory"])
|
|
|
|
if assembly_process == "THT":
|
|
assembly_process = "Hand-Soldered"
|
|
joint_cost = hand_solder_joint_cost
|
|
else:
|
|
joint_cost = smt_joint_cost
|
|
|
|
try:
|
|
price_json = json.loads(df.loc[index, "price"])
|
|
if price_json and len(price_json) > 0 and "price" in price_json[0]:
|
|
base_price = float(price_json[0]["price"])
|
|
# Calculate the total price considering joints and joint cost
|
|
price = base_price + (joints * joint_cost)
|
|
price = round(price, 3)
|
|
price_str = f"{price:.3f}USD"
|
|
|
|
else:
|
|
price_str = f""
|
|
print(f"Error: Price is missing or invalid for https://jlcpcb.com/partdetail/C{lcsc} ({price_json})")
|
|
except (json.JSONDecodeError, ValueError, KeyError, TypeError):
|
|
price_str = f""
|
|
print(f"Error: Price cannot be parsed https://jlcpcb.com/partdetail/C{lcsc}")
|
|
|
|
if price > 3.0 or footprint_name == "0201" or lcsc == 882967 or stock < min_order_qty:
|
|
df.drop(index=index, inplace=True)
|
|
else:
|
|
component_class = get_basic_or_prefered_type(df, index)
|
|
keywords = ""
|
|
value = None
|
|
|
|
datasheet = df.loc[index, "datasheet"]
|
|
|
|
try:
|
|
extra_json = json.loads(df.loc[index, "extra"])
|
|
attributes = extra_json["attributes"]
|
|
attributes = {key: value for key, value in attributes.items() if value != "-"}
|
|
except:
|
|
attributes = {}
|
|
|
|
component_properties = {
|
|
"price": price_str,
|
|
"stock": stock,
|
|
"datasheet": datasheet,
|
|
"description": description,
|
|
"process": assembly_process,
|
|
"minimum qty": min_order_qty,
|
|
"attrition qty": attrition_qty,
|
|
"class": component_class,
|
|
"category": category,
|
|
"manufacturer": manufacturer,
|
|
"part": manufacturerPartID,
|
|
}
|
|
|
|
component_properties = {**component_properties, **attributes}
|
|
|
|
if df.loc[index, "category"] == "Resistors" and lcsc != 2909989:
|
|
value = extract_resistance_value(description, lcsc)
|
|
if "x4" in footprint_name:
|
|
units = 4
|
|
lib_name = "Resistors"
|
|
|
|
elif df.loc[index, "category"] == "Capacitors":
|
|
value = extract_capacitor_value(description, lcsc)
|
|
lib_name = "Capacitors"
|
|
if lcsc == 360353:
|
|
footprint_name = "Plugin,P=5mm"
|
|
if attributes == {}:
|
|
# {'Voltage Rated': '50V', 'Tolerance': '±5%', 'Capacitance': '15pF', 'Temperature Coefficient': 'NP0'}
|
|
capacitor_voltage = extract_capacitor_voltage(description, lcsc)
|
|
if capacitor_voltage != None:
|
|
attributes = {"Voltage Rated": capacitor_voltage}
|
|
|
|
elif df.loc[index, "category"] == "Diodes" or ("TVS" in subcategory) or ("ESD" in subcategory):
|
|
value = extract_diode_type(description, joints, lcsc)
|
|
secondary_mode = value
|
|
lib_name = "Diodes"
|
|
if value == None:
|
|
if update_component_inplace(lcsc, "Diode-Packages", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif subcategory == "Light Emitting Diodes (LED)" or "LED" in description:
|
|
if lcsc == 2895565 or lcsc == 2835341:
|
|
if update_component_inplace(lcsc, "Diode-Packages", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
else:
|
|
value, secondary_mode = extract_LED_value(description, lcsc)
|
|
lib_name = "Diodes"
|
|
|
|
elif (
|
|
subcategory == "MOSFETs"
|
|
or (subcategory == "Bipolar Transistors - BJT")
|
|
or (subcategory == "Bipolar (BJT)")
|
|
or (df.loc[index, "category"] == "Triode/MOS Tube/Transistor")
|
|
or (df.loc[index, "category"] == "Transistors")
|
|
or (df.loc[index, "category"] == "Transistors/Thyristors")
|
|
):
|
|
if footprint_name == "SOT-23-3L" or footprint_name == "SOT-23-3":
|
|
footprint_name = "SOT-23"
|
|
elif footprint_name == "SOT-89-3":
|
|
footprint_name = "SOT-89"
|
|
|
|
value = extract_transistor_type(description, joints, footprint_name, lcsc)
|
|
secondary_mode = value
|
|
lib_name = "Transistors"
|
|
if value == None:
|
|
if update_component_inplace(lcsc, "Transistor-Packages", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif subcategory == "Inductors (SMD)" or (subcategory == "Ferrite Beads") or (subcategory == "Power Inductors"):
|
|
value, secondary_mode = extract_inductor_type_value(description, joints, lcsc)
|
|
lib_name = "Inductors"
|
|
|
|
elif subcategory == "Crystals" or subcategory == "Oscillators":
|
|
if update_component_inplace(lcsc, "Crystals", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
subcategory == "NTC Thermistors"
|
|
or (subcategory == "Varistors")
|
|
or (subcategory == "Fuses")
|
|
or (subcategory == "Resettable Fuses")
|
|
):
|
|
secondary_mode, value = extract_variable_resistor_type_value(description, lcsc)
|
|
lib_name = "Variable-Resistors"
|
|
if lcsc == 210465:
|
|
footprint_name = "Plugin,P=5mm"
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Embedded Processors & Controllers"
|
|
or df.loc[index, "category"] == "Single Chip Microcomputer/Microcontroller"
|
|
or df.loc[index, "category"] == "IoT/Communication Modules"
|
|
):
|
|
del component_properties["datasheet"]
|
|
del component_properties["description"]
|
|
if update_component_inplace(lcsc, "MCUs", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Connectors"
|
|
or (df.loc[index, "category"] == "Key/Switch")
|
|
or (df.loc[index, "category"] == "Switches")
|
|
or (lcsc == 2909989)
|
|
):
|
|
if update_component_inplace(lcsc, "Connectors_Buttons", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Power Management"
|
|
or (df.loc[index, "category"] == "Power Management ICs")
|
|
or (lcsc == 394180)
|
|
):
|
|
if update_component_inplace(lcsc, "Power", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Amplifiers"
|
|
or (df.loc[index, "category"] == "Operational Amplifier/Comparator")
|
|
or subcategory == "Analog Switches / Multiplexers"
|
|
or subcategory == "Digital Potentiometers"
|
|
):
|
|
if update_component_inplace(lcsc, "Analog", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif df.loc[index, "category"] == "Memory":
|
|
if update_component_inplace(lcsc, "Memory", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Communication Interface Chip"
|
|
or (df.loc[index, "category"] == "Communication Interface Chip/UART/485/232")
|
|
or (df.loc[index, "category"] == "Interface ICs")
|
|
or (df.loc[index, "category"] == "Signal Isolation Devices")
|
|
or df.loc[index, "category"] == "Nixie Tube Driver/LED Driver"
|
|
or (subcategory == "LCD Drivers")
|
|
):
|
|
if update_component_inplace(lcsc, "Interface", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
subcategory == "Current Transformers"
|
|
or (subcategory == "Common Mode Filters")
|
|
or (subcategory == "Color Ring Inductors / Through Hole Inductors")
|
|
):
|
|
if update_component_inplace(lcsc, "Transformers", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Optocoupler"
|
|
or df.loc[index, "category"] == "Optoisolators"
|
|
or (subcategory == "Optocouplers")
|
|
or (subcategory == "Optocouplers - Phototransistor Output")
|
|
or (subcategory == "Reflective Optical Interrupters")
|
|
):
|
|
if update_component_inplace(lcsc, "Optocouplers", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
elif (
|
|
df.loc[index, "category"] == "Logic ICs"
|
|
or (subcategory == "Real-time Clocks (RTC)")
|
|
or (subcategory == "Timers / Clock Oscillators")
|
|
or (subcategory == "Real-Time Clocks(RTC)")
|
|
or (subcategory == "Clock Buffers/Drivers/Distributions")
|
|
or (subcategory == "Hall Sensor")
|
|
):
|
|
if update_component_inplace(lcsc, "ICs", component_properties) == True:
|
|
df.drop(index=index, inplace=True)
|
|
|
|
if value != None:
|
|
df.drop(index=index, inplace=True)
|
|
symbol = generate_kicad_symbol(
|
|
lib_name,
|
|
secondary_mode,
|
|
lcsc,
|
|
datasheet,
|
|
description,
|
|
footprint_name,
|
|
value,
|
|
keywords,
|
|
price_str,
|
|
assembly_process,
|
|
min_order_qty,
|
|
attrition_qty,
|
|
component_class,
|
|
stock,
|
|
category,
|
|
manufacturer,
|
|
manufacturerPartID,
|
|
attributes,
|
|
units,
|
|
footprints_lookup,
|
|
names_lookup,
|
|
)
|
|
symbols[lib_name].append(symbol)
|
|
|
|
df.to_csv("leftover.csv", index=False)
|
|
|
|
generate_kicad_symbol_libs(symbols)
|
|
|
|
update_library_stock_inplace("Analog")
|
|
update_library_stock_inplace("Connectors_Buttons")
|
|
update_library_stock_inplace("Crystals")
|
|
update_library_stock_inplace("Diode-Packages")
|
|
update_library_stock_inplace("ICs")
|
|
update_library_stock_inplace("Interface")
|
|
update_library_stock_inplace("Memory")
|
|
update_library_stock_inplace("MCUs")
|
|
update_library_stock_inplace("Optocouplers")
|
|
update_library_stock_inplace("Power")
|
|
update_library_stock_inplace("Transformers")
|
|
update_library_stock_inplace("Transistor-Packages")
|
|
|
|
check_footprints()
|
|
check_models()
|
|
|
|
files_and_dirs = ["3dmodels", "footprints", "resources", "symbols", "metadata.json"]
|
|
current_date = datetime.now(timezone.utc).strftime("%Y.%m.%d")
|
|
|
|
update_version("metadata.json", current_date)
|
|
create_zip_archive(f"JLCPCB-KiCad-Library-{current_date}.zip", files_and_dirs)
|