124 lines
3.4 KiB
Python
124 lines
3.4 KiB
Python
# BOM generation script for KiCAD (6+)
|
|
# Last update: 26/03/2025
|
|
# Author: Jorian Zwerver
|
|
|
|
# This scripts formats the BOM to the format of SPECTRUM with PRICES
|
|
|
|
"""
|
|
@package
|
|
Generate a comma delimited list (csv file type) in SPECTRUM style.
|
|
Components are sorted by reference and grouped by value.
|
|
Fields are (if exist)
|
|
'References', 'Value', 'MPN', 'Manufacturer', 'Description', 'Farnell', 'Mouser', 'Digikey', 'LCSC', 'Quantity'
|
|
|
|
Command line:
|
|
python "pathToFile/SpecLib/BOM scripts/spectrum_bom_general.py" "%I" "%O_BOM_GENERAL.csv"
|
|
"""
|
|
|
|
# Import libraries
|
|
from libs import pymouser
|
|
from libs import kicad_netlist_reader
|
|
from libs import dotenv
|
|
import sys
|
|
import csv
|
|
import sys
|
|
import os
|
|
import time
|
|
|
|
# Get netlist from schematic
|
|
net = kicad_netlist_reader.netlist(sys.argv[1])
|
|
|
|
# Load API keys
|
|
dotenv.load_dotenv()
|
|
|
|
# Initialize the package with the API key
|
|
MOUSER_API_KEY = os.getenv("MOUSER_API_KEY")
|
|
|
|
if MOUSER_API_KEY == None:
|
|
raise Exception("No .env file found. Please download the .env file from the Google Drive.")
|
|
|
|
mouser = pymouser.MouserAPI(MOUSER_API_KEY)
|
|
|
|
# Function to interface with Mouser API
|
|
def get_price_from_mouser(mpn, n) -> float:
|
|
err, res = mouser.search_by_PN(mpn)
|
|
|
|
if err:
|
|
print("Error during request:")
|
|
print(err)
|
|
return 0.0
|
|
else:
|
|
if res['NumberOfResult'] == 0:
|
|
print("No results matched the part number")
|
|
return 0.0
|
|
else:
|
|
part_prices = res['Parts'][0]['PriceBreaks']
|
|
|
|
if not part_prices:
|
|
return 0.0
|
|
|
|
for price in part_prices:
|
|
if(n >= price['Quantity']):
|
|
value = price['Price'][2:].replace(",",".")
|
|
else:
|
|
break
|
|
return n*float(value)
|
|
|
|
# Open CSV file
|
|
try:
|
|
f = open(sys.argv[2], 'w')
|
|
except IOError:
|
|
e = "Can't open output file for writing: " + sys.argv[2]
|
|
print(__file__, ":", e, sys.stderr)
|
|
f = sys.stdout
|
|
|
|
# Generate new CSV file with header
|
|
out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL)
|
|
out.writerow(['References', 'Value', 'MPN', 'Manufacturer', 'Description', 'Farnell', 'Mouser', 'Mouser Price', 'Digikey', 'LCSC', 'Quantity'])
|
|
|
|
# Generate groups
|
|
grouped = net.groupComponents()
|
|
|
|
# Keep track of API requests
|
|
request_cnt = 0
|
|
|
|
# Iterate over each group
|
|
for group in grouped:
|
|
# Get all component references neatly grouped together
|
|
refs = ", ".join(component.getRef() for component in group)
|
|
component = group[0]
|
|
|
|
# Component quantity
|
|
n = len(group)
|
|
# Mouser MPN
|
|
mouser_mpn = component.getField('Mouser')
|
|
|
|
# If there is a Mouser MPN, get component price
|
|
if not mouser_mpn:
|
|
mouser_price = 0.0
|
|
else:
|
|
mouser_price = get_price_from_mouser(mouser_mpn, n)
|
|
request_cnt = request_cnt + 1
|
|
|
|
# If too many requests, wait for a bit
|
|
if(request_cnt > 29):
|
|
print("30 request limit reached. Waiting for one minute.")
|
|
time.sleep(60)
|
|
request_cnt = 0
|
|
|
|
# Store all data in CSV
|
|
out.writerow([
|
|
refs,
|
|
component.getValue(),
|
|
component.getField('MPN'),
|
|
component.getField('Manufacturer'),
|
|
component.getDescription(),
|
|
component.getField('Farnell'),
|
|
mouser_mpn,
|
|
mouser_price,
|
|
component.getField('Digikey'),
|
|
component.getField('LCSC'),
|
|
n
|
|
])
|
|
|
|
print("All done!") |