-
-
Save gcormier/61addd28226bfd4ed6f645f312c3f13a to your computer and use it in GitHub Desktop.
| """ | |
| @package | |
| Output: CSV (comma-separated) | |
| Grouped By: Value | |
| Sorted By: Ref | |
| Fields: Comment,Designator,Footprint,LCSC | |
| Outputs the BOM for JLCPCB. Run this AFTER generating your POS file for SMT assembly. | |
| Attempts to find and modify POS header to JLC format in the same output folder. | |
| REQUIRES kicad_utils.py and kicad_netlist_reader.py in the same director as this script | |
| https://gitlab.com/kicad/code/kicad/-/tree/master/eeschema/plugins/python_scripts | |
| Command line: | |
| python "pathToFile/bom_csv_grouped_by_value.py" "%I" "%O.csv" | |
| Using a gerber output subfolder: | |
| python "pathToFile/bom_csv_grouped_by_value.py" "%I" "%P/gerber/%B-bom.csv" | |
| """ | |
| from __future__ import print_function | |
| # Import the KiCad python helper module and the csv formatter | |
| import kicad_netlist_reader | |
| import kicad_utils | |
| import csv | |
| import sys | |
| import os | |
| # A helper function to convert a UTF8/Unicode/locale string read in netlist | |
| # for python2 or python3 (Windows/unix) | |
| def fromNetlistText( aText ): | |
| currpage = sys.stdout.encoding #the current code page. can be none | |
| if currpage is None: | |
| return aText | |
| if currpage != 'utf-8': | |
| try: | |
| return aText.encode('utf-8').decode(currpage) | |
| except UnicodeDecodeError: | |
| return aText | |
| else: | |
| return aText | |
| def myEqu(self, other): | |
| """myEqu is a more advanced equivalence function for components which is | |
| used by component grouping. Normal operation is to group components based | |
| on their value and footprint. | |
| In this example of a custom equivalency operator we compare the | |
| value, the part name and the footprint. | |
| """ | |
| result = True | |
| if self.getValue() != other.getValue(): | |
| result = False | |
| elif self.getPartName() != other.getPartName(): | |
| result = False | |
| elif self.getFootprint() != other.getFootprint(): | |
| result = False | |
| return result | |
| # Override the component equivalence operator - it is important to do this | |
| # before loading the netlist, otherwise all components will have the original | |
| # equivalency operator. | |
| kicad_netlist_reader.comp.__eq__ = myEqu | |
| if len(sys.argv) != 3: | |
| print("Usage ", __file__, "<generic_netlist.xml> <output.csv>", file=sys.stderr) | |
| sys.exit(1) | |
| # Generate an instance of a generic netlist, and load the netlist tree from | |
| # the command line option. If the file doesn't exist, execution will stop | |
| net = kicad_netlist_reader.netlist(sys.argv[1]) | |
| # Open a file to write to, if the file cannot be opened output to stdout | |
| # instead | |
| try: | |
| f = kicad_utils.open_file_write(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 | |
| # subset the components to those wanted in the BOM, controlled | |
| # by <configure> block in kicad_netlist_reader.py | |
| components = net.getInterestingComponents() | |
| compfields = net.gatherComponentFieldUnion(components) | |
| partfields = net.gatherLibPartFieldUnion() | |
| # remove Reference, Value, Datasheet, and Footprint, they will come from 'columns' below | |
| partfields -= set( ['Reference', 'Value', 'Datasheet', 'Footprint'] ) | |
| columnset = compfields | partfields # union | |
| # prepend an initial 'hard coded' list and put the enchillada into list 'columns' | |
| columns = ['Comment', 'Designator', 'Footprint', 'LCSC'] | |
| # Create a new csv writer object to use as the output formatter | |
| out = csv.writer( f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL ) | |
| # override csv.writer's writerow() to support encoding conversion (initial encoding is utf8): | |
| def writerow( acsvwriter, columns ): | |
| utf8row = [] | |
| for col in columns: | |
| utf8row.append( fromNetlistText( str(col) ) ) | |
| acsvwriter.writerow( utf8row ) | |
| writerow( out, columns ) | |
| # Output all the interesting components individually first: | |
| row = [] | |
| for c in components: | |
| del row[:] | |
| row.append('') # item is blank in individual table | |
| row.append('') # Qty is always 1, why print it | |
| row.append( c.getRef() ) # Reference | |
| row.append( c.getValue() ) # Value | |
| row.append( c.getLibName() + ":" + c.getPartName() ) # LibPart | |
| #row.append( c.getDescription() ) | |
| row.append( c.getFootprint() ) | |
| row.append( c.getDatasheet() ) | |
| # from column 7 upwards, use the fieldnames to grab the data | |
| for field in columns[7:]: | |
| row.append( c.getField( field ) ); | |
| # Get all of the components in groups of matching parts + values | |
| # (see kicad_netlist_reader.py) | |
| grouped = net.groupComponents(components) | |
| # Output component information organized by group, aka as collated: | |
| item = 0 | |
| for group in grouped: | |
| del row[:] | |
| refs = "" | |
| # Add the reference of every component in the group and keep a reference | |
| # to the component so that the other data can be filled in once per group | |
| for component in group: | |
| if len(refs) > 0: | |
| refs += ", " | |
| refs += component.getRef() | |
| c = component | |
| # Fill in the component groups common data | |
| # columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) | |
| item += 1 | |
| row.append( c.getValue() ) | |
| row.append( refs ); | |
| row.append( net.getGroupFootprint(group) ) | |
| row.append( c.getField('LCSC') ) | |
| # from column 7 upwards, use the fieldnames to grab the data | |
| for field in columns[7:]: | |
| row.append( net.getGroupField(group, field) ); | |
| writerow( out, row ) | |
| f.close() | |
| # Try to see if POS files exist. If so, modify them to the JLCPCB header | |
| # Looks for a few permutations defined in fileOptions which depends if user selected a single POS | |
| # or if they select seperate for layers | |
| inputFile = os.path.split(sys.argv[1])[1] | |
| projectName = os.path.splitext(inputFile)[0] | |
| destination = sys.argv[2] | |
| destinationPath = os.path.dirname(destination) | |
| print("Project name detected as :", projectName) | |
| fileOptions = [ '-all-pos', '-top-pos', '-bottom-pos'] | |
| for possibility in fileOptions: | |
| positionFile = destinationPath + "/" + projectName + possibility + ".csv" | |
| print("\nChecking for existance of ", positionFile) | |
| if os.path.isfile(positionFile): | |
| print("Modifying header of ", positionFile) | |
| with open(positionFile) as f: | |
| lines = f.readlines() | |
| lines[0] = "Designator,Val,Package,Mid X,Mid Y,Rotation,Layer\n" | |
| with open(positionFile, "w") as f: | |
| f.writelines(lines) | |
| else: | |
| print("Not found (" + positionFile + ")") | |
Any chance you can get together with this dev? because i like the idea of this just being a plugin instead of running command line scripts. https://github.com/bennymeg/JLC-Plugin-for-KiCad
lines 113 to 129 are useless, remove them
then fix line 138 " raw = [] "
What is the point of counting 'item' ? It serves nothing. (lines 136, 151)
Lines 156..158 also useless !
Line 186 brakes what JLC is expecting ??????!!!!!!!
Designator, ~~Val,Package, ~~ Mid X,Mid Y,Rotation,Layer
I got here from https://www.youtube.com/watch?v=v9FglN80EMM then https://jlcpcb.com/help/article/81-How-to-generate-the-BOM-and-Centroid-file-from-KiCAD then https://gist.github.com/arturo182/a8c4a4b96907cfccf616a1edb59d0389
What I did not get anywhere was an idea how to install and how to use this python file.
I am using Windows 10.
Thank you!