Simplified build-quantity option
This commit is contained in:
parent
9533079520
commit
13ad8dbd3c
|
|
@ -11,7 +11,7 @@ class ColumnList:
|
||||||
COL_DATASHEET = 'Datasheet'
|
COL_DATASHEET = 'Datasheet'
|
||||||
|
|
||||||
#default columns for groups
|
#default columns for groups
|
||||||
COL_GRP_QUANTITY = 'Quantity'
|
COL_GRP_QUANTITY = 'Quantity Per PCB'
|
||||||
COL_GRP_TOTAL_COST = 'Total Cost' #Total cost based on quantity
|
COL_GRP_TOTAL_COST = 'Total Cost' #Total cost based on quantity
|
||||||
COL_GRP_BUILD_QUANTITY = 'Build Quantity'
|
COL_GRP_BUILD_QUANTITY = 'Build Quantity'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ class ComponentGroup():
|
||||||
self.fields[ColumnList.COL_GRP_QUANTITY] = "{n}{dnf}".format(
|
self.fields[ColumnList.COL_GRP_QUANTITY] = "{n}{dnf}".format(
|
||||||
n=q,
|
n=q,
|
||||||
dnf = " (DNF)" if not self.isFitted() else "")
|
dnf = " (DNF)" if not self.isFitted() else "")
|
||||||
self.fields[ColumnList.COL_GRP_BUILD_QUANTITY] = str(q * self.prefs.buildNumber) if self.isFitted() else "0"
|
self.fields[ColumnList.COL_GRP_BUILD_QUANTITY] = str(q * self.prefs.boards) if self.isFitted() else "0"
|
||||||
self.fields[ColumnList.COL_VALUE] = self.components[0].getValue()
|
self.fields[ColumnList.COL_VALUE] = self.components[0].getValue()
|
||||||
self.fields[ColumnList.COL_PART] = self.components[0].getPartName()
|
self.fields[ColumnList.COL_PART] = self.components[0].getPartName()
|
||||||
self.fields[ColumnList.COL_PART_LIB] = self.components[0].getLibName()
|
self.fields[ColumnList.COL_PART_LIB] = self.components[0].getLibName()
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ def WriteCSV(filename, groups, net, headings, prefs):
|
||||||
nGroups = len(groups)
|
nGroups = len(groups)
|
||||||
nTotal = sum([g.getCount() for g in groups])
|
nTotal = sum([g.getCount() for g in groups])
|
||||||
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
|
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
|
||||||
nBuild = nFitted * prefs.buildNumber
|
nBuild = nFitted * prefs.boards
|
||||||
|
|
||||||
with open(filename, "w") as f:
|
with open(filename, "w") as f:
|
||||||
|
|
||||||
|
|
@ -70,9 +70,8 @@ def WriteCSV(filename, groups, net, headings, prefs):
|
||||||
writer.writerow(["Component Groups:",nGroups])
|
writer.writerow(["Component Groups:",nGroups])
|
||||||
writer.writerow(["Component Count:",nTotal])
|
writer.writerow(["Component Count:",nTotal])
|
||||||
writer.writerow(["Fitted Components:", nFitted])
|
writer.writerow(["Fitted Components:", nFitted])
|
||||||
if prefs.buildNumber > 0:
|
writer.writerow(["Number of PCBs:",prefs.boards])
|
||||||
writer.writerow(["Number of PCBs:",prefs.buildNumber])
|
writer.writerow(["Total components:", nBuild])
|
||||||
writer.writerow(["Total components:", nBuild])
|
|
||||||
writer.writerow(["Schematic Version:",net.getVersion()])
|
writer.writerow(["Schematic Version:",net.getVersion()])
|
||||||
writer.writerow(["Schematic Date:",net.getSheetDate()])
|
writer.writerow(["Schematic Date:",net.getSheetDate()])
|
||||||
writer.writerow(["BoM Date:",net.getDate()])
|
writer.writerow(["BoM Date:",net.getDate()])
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ def WriteHTML(filename, groups, net, headings, prefs):
|
||||||
nGroups = len(groups)
|
nGroups = len(groups)
|
||||||
nTotal = sum([g.getCount() for g in groups])
|
nTotal = sum([g.getCount() for g in groups])
|
||||||
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
|
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
|
||||||
nBuild = nFitted * prefs.buildNumber
|
nBuild = nFitted * prefs.boards
|
||||||
|
|
||||||
with open(filename,"w") as html:
|
with open(filename,"w") as html:
|
||||||
|
|
||||||
|
|
@ -68,9 +68,8 @@ def WriteHTML(filename, groups, net, headings, prefs):
|
||||||
html.write("<tr><td>Component Groups</td><td>{n}</td></tr>\n".format(n=nGroups))
|
html.write("<tr><td>Component Groups</td><td>{n}</td></tr>\n".format(n=nGroups))
|
||||||
html.write("<tr><td>Component Count (per PCB)</td><td>{n}</td></tr>\n".format(n=nTotal))
|
html.write("<tr><td>Component Count (per PCB)</td><td>{n}</td></tr>\n".format(n=nTotal))
|
||||||
html.write("<tr><td>Fitted Components (per PCB)</td><td>{n}</td></tr>\n".format(n=nFitted))
|
html.write("<tr><td>Fitted Components (per PCB)</td><td>{n}</td></tr>\n".format(n=nFitted))
|
||||||
if prefs.buildNumber > 0:
|
html.write("<tr><td>Number of PCBs</td><td>{n}</td></tr>\n".format(n=prefs.boards))
|
||||||
html.write("<tr><td>Number of PCBs</td><td>{n}</td></tr>\n".format(n=prefs.buildNumber))
|
html.write("<tr><td>Total Component Count<br>(for {n} PCBs)</td><td>{t}</td></tr>\n".format(n=prefs.boards, t=nBuild))
|
||||||
html.write("<tr><td>Total Component Count<br>(for {n} PCBs)</td><td>{t}</td></tr>\n".format(n=prefs.buildNumber, t=nBuild))
|
|
||||||
html.write("</table>\n")
|
html.write("</table>\n")
|
||||||
html.write("<br>\n")
|
html.write("<br>\n")
|
||||||
html.write("<h2>Component Groups</h2>\n")
|
html.write("<h2>Component Groups</h2>\n")
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ class BomPref:
|
||||||
OPT_USE_REGEX = "test_regex"
|
OPT_USE_REGEX = "test_regex"
|
||||||
OPT_COMP_FP = "compare_footprints"
|
OPT_COMP_FP = "compare_footprints"
|
||||||
OPT_INC_PRICE = "calculate_price"
|
OPT_INC_PRICE = "calculate_price"
|
||||||
OPT_BUILD_NUMBER = 'build_quantity'
|
|
||||||
|
|
||||||
#list of columns which we can use regex on
|
#list of columns which we can use regex on
|
||||||
COL_REG_EX = [
|
COL_REG_EX = [
|
||||||
|
|
@ -49,28 +48,9 @@ class BomPref:
|
||||||
self.groupConnectors = True #group connectors and ignore component value
|
self.groupConnectors = True #group connectors and ignore component value
|
||||||
self.useRegex = True #Test various columns with regex
|
self.useRegex = True #Test various columns with regex
|
||||||
self.compareFootprints = True #test footprints when comparing components
|
self.compareFootprints = True #test footprints when comparing components
|
||||||
self.buildNumber = 0
|
self.boards = 1
|
||||||
self.verbose = False #by default, is not verbose
|
self.verbose = False #by default, is not verbose
|
||||||
self.configurations = [] #list of various configurations
|
self.configurations = [] #list of various configurations
|
||||||
|
|
||||||
#default reference exclusions
|
|
||||||
self.excluded_references = [
|
|
||||||
"TP[0-9]+"
|
|
||||||
]
|
|
||||||
|
|
||||||
#default value exclusions
|
|
||||||
self.excluded_values = [
|
|
||||||
'MOUNTHOLE',
|
|
||||||
'SCOPETEST',
|
|
||||||
'MOUNT_HOLE',
|
|
||||||
'MOUNTING_HOLE',
|
|
||||||
'SOLDER_BRIDGE.*',
|
|
||||||
'test'
|
|
||||||
]
|
|
||||||
|
|
||||||
#default footprint exclusions
|
|
||||||
self.excluded_footprints = [
|
|
||||||
]
|
|
||||||
|
|
||||||
#default component groupings
|
#default component groupings
|
||||||
self.aliases = [
|
self.aliases = [
|
||||||
|
|
@ -131,14 +111,6 @@ class BomPref:
|
||||||
self.groupConnectors = self.checkOption(cf, self.OPT_GROUP_CONN, default=True)
|
self.groupConnectors = self.checkOption(cf, self.OPT_GROUP_CONN, default=True)
|
||||||
self.useRegex = self.checkOption(cf, self.OPT_USE_REGEX, default=True)
|
self.useRegex = self.checkOption(cf, self.OPT_USE_REGEX, default=True)
|
||||||
self.compareFootprints = self.checkOption(cf, self.OPT_COMP_FP, default=True)
|
self.compareFootprints = self.checkOption(cf, self.OPT_COMP_FP, default=True)
|
||||||
|
|
||||||
if cf.has_option(self.SECTION_GENERAL, self.OPT_BUILD_NUMBER):
|
|
||||||
try:
|
|
||||||
self.buildNumber = int(cf.get(self.SECTION_GENERAL, self.OPT_BUILD_NUMBER))
|
|
||||||
if self.buildNumber < 1:
|
|
||||||
self.buildNumber = 0
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
#read out configurations
|
#read out configurations
|
||||||
if self.SECTION_CONFIGURATIONS in cf.sections():
|
if self.SECTION_CONFIGURATIONS in cf.sections():
|
||||||
|
|
@ -180,7 +152,6 @@ class BomPref:
|
||||||
self.addOption(cf, self.OPT_GROUP_CONN, self.groupConnectors, comment="If '{opt}' option is set to 1, connectors with the same footprints will be grouped together, independent of the name of the connector".format(opt=self.OPT_GROUP_CONN))
|
self.addOption(cf, self.OPT_GROUP_CONN, self.groupConnectors, comment="If '{opt}' option is set to 1, connectors with the same footprints will be grouped together, independent of the name of the connector".format(opt=self.OPT_GROUP_CONN))
|
||||||
self.addOption(cf, self.OPT_USE_REGEX, self.useRegex, comment="If '{opt}' option is set to 1, each component group will be tested against a number of regular-expressions (specified, per column, below). If any matches are found, the row is ignored in the output file".format(opt=self.OPT_USE_REGEX))
|
self.addOption(cf, self.OPT_USE_REGEX, self.useRegex, comment="If '{opt}' option is set to 1, each component group will be tested against a number of regular-expressions (specified, per column, below). If any matches are found, the row is ignored in the output file".format(opt=self.OPT_USE_REGEX))
|
||||||
self.addOption(cf, self.OPT_COMP_FP, self.compareFootprints, comment="If '{opt}' option is set to 1, two components must have the same footprint to be grouped together. If '{opt}' is not set, then footprint comparison is ignored.".format(opt=self.OPT_COMP_FP))
|
self.addOption(cf, self.OPT_COMP_FP, self.compareFootprints, comment="If '{opt}' option is set to 1, two components must have the same footprint to be grouped together. If '{opt}' is not set, then footprint comparison is ignored.".format(opt=self.OPT_COMP_FP))
|
||||||
self.addOption(cf, self.OPT_BUILD_NUMBER, self.buildNumber, comment="; '{opt}' is the number of boards to build, which is used to calculate total parts quantity. If this is set to zero (0) then it is ignored".format(opt=self.OPT_BUILD_NUMBER))
|
|
||||||
|
|
||||||
cf.add_section(self.SECTION_IGNORE)
|
cf.add_section(self.SECTION_IGNORE)
|
||||||
cf.set(self.SECTION_IGNORE, "; Any column heading that appears here will be excluded from the Generated BoM")
|
cf.set(self.SECTION_IGNORE, "; Any column heading that appears here will be excluded from the Generated BoM")
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ def WriteXML(filename, groups, net, headings, prefs):
|
||||||
nGroups = len(groups)
|
nGroups = len(groups)
|
||||||
nTotal = sum([g.getCount() for g in groups])
|
nTotal = sum([g.getCount() for g in groups])
|
||||||
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
|
nFitted = sum([g.getCount() for g in groups if g.isFitted()])
|
||||||
nBuild = nFitted * prefs.buildNumber
|
nBuild = nFitted * prefs.boards
|
||||||
|
|
||||||
attrib = {}
|
attrib = {}
|
||||||
|
|
||||||
|
|
@ -34,9 +34,8 @@ def WriteXML(filename, groups, net, headings, prefs):
|
||||||
attrib['Component_Count'] = str(nTotal)
|
attrib['Component_Count'] = str(nTotal)
|
||||||
attrib['Fitted_Components'] = str(nFitted)
|
attrib['Fitted_Components'] = str(nFitted)
|
||||||
|
|
||||||
if prefs.buildNumber > 0:
|
attrib['Number_of_PCBs'] = str(prefs.boards)
|
||||||
attrib['Number_of_PCBs'] = str(prefs.buildNumber)
|
attrib['Total_Components'] = str(nBuild)
|
||||||
attrib['Total_Components'] = str(nBuild)
|
|
||||||
|
|
||||||
xml = ElementTree.Element('KiCAD_BOM', attrib = attrib, encoding='utf-8')
|
xml = ElementTree.Element('KiCAD_BOM', attrib = attrib, encoding='utf-8')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ parser = argparse.ArgumentParser(description="KiBOM Bill of Materials generator
|
||||||
|
|
||||||
parser.add_argument("netlist", help='xml netlist file. Use "%%I" when running from within KiCad')
|
parser.add_argument("netlist", help='xml netlist file. Use "%%I" when running from within KiCad')
|
||||||
parser.add_argument("--output", "-o", help='BoM output file name.\nUse "%%O" when running from within KiCad to use the default output name (csv file).\nFor e.g. HTML output, use "%%O.html"\r\nIf output file is unspecified, default output filename (csv format) will be used', default=None)
|
parser.add_argument("--output", "-o", help='BoM output file name.\nUse "%%O" when running from within KiCad to use the default output name (csv file).\nFor e.g. HTML output, use "%%O.html"\r\nIf output file is unspecified, default output filename (csv format) will be used', default=None)
|
||||||
|
parser.add_argument("--boards", "-b", help="Number of boards to build (default = 1)", type=int, default=1)
|
||||||
parser.add_argument("-v", "--verbose", help="Enable verbose output", action='count')
|
parser.add_argument("-v", "--verbose", help="Enable verbose output", action='count')
|
||||||
parser.add_argument("--cfg", help="BoM config file (script will try to use 'bom.ini' if not specified here)")
|
parser.add_argument("--cfg", help="BoM config file (script will try to use 'bom.ini' if not specified here)")
|
||||||
|
|
||||||
|
|
@ -80,8 +80,9 @@ if args.cfg:
|
||||||
#read preferences from file. If file does not exists, default preferences will be used
|
#read preferences from file. If file does not exists, default preferences will be used
|
||||||
pref = BomPref()
|
pref = BomPref()
|
||||||
|
|
||||||
#verbosity options
|
#pass various command-line options through
|
||||||
pref.verbose = verbose
|
pref.verbose = verbose
|
||||||
|
pref.boards = args.boards
|
||||||
|
|
||||||
if os.path.exists(config_file):
|
if os.path.exists(config_file):
|
||||||
pref.Read(config_file)
|
pref.Read(config_file)
|
||||||
|
|
@ -114,7 +115,7 @@ for g in groups:
|
||||||
for f in g.fields:
|
for f in g.fields:
|
||||||
columns.AddColumn(f)
|
columns.AddColumn(f)
|
||||||
|
|
||||||
if pref.buildNumber < 1:
|
if pref.boards <= 1:
|
||||||
columns.RemoveColumn(ColumnList.COL_GRP_BUILD_QUANTITY)
|
columns.RemoveColumn(ColumnList.COL_GRP_BUILD_QUANTITY)
|
||||||
say("Removing:",ColumnList.COL_GRP_BUILD_QUANTITY)
|
say("Removing:",ColumnList.COL_GRP_BUILD_QUANTITY)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue