pimpmykicadbom

KiCad BOM tool
This tool reads the XML BOM files which KiCad (Eeschema) generates.
It processes them and outputs .html and .csv files.
The code is on GitLab.


There are two modes of operation

  • As a plugin (from Eeschema):
    Processes a single BOM

  • Standalone (command line):
    Processes one or more BOMs, multiplies the component quantities (for each input BOM), groups the components to a single output.
    This usage can be useful for making a final BOM for ordering components for multiple projects.

Features

  • Configurable grouping, sorting, and column order

  • Final BOM generation (multiplying component quantities of BOMs and merging to a final BOM)

  • Generates a simplified "Package" name from the Footprint name (via configurable regex replace)

  • Values for passive components are parsed and optimized, useful for sorting (applies for resistors, capacitors, inductors, and crystals)

  • BOM output filename and sub-directory is configurable (for plugin mode)

  • Colorful HTML output - pseudo-random background color (HTML BOMs only) could help make different components stand out.. or maybe not.. but it looks cool!

  • Custom Fields supported - particular custom fields can be positioned precisely or excluded from the BOM, all remaining unspecified Custom Fields can be put at one place or excluded (via config).

Requirements

Code::Blocks project provided
The tool should run on Linux, Windows, etc..

Building on Debian:

  • install libtinyxml2-dev

  • open the .cbp project file with Code::Blocks

  • make sure the "linuxRelease" target is selected

  • press Build

Building on Windows (mingw):

  • get tinyxml2

  • make sure it is placed in the parent folder

  • open the .cbp project file with Code::Blocks

  • if it complains that gnu_gcc_compiler_mingw-w64 isn’t there - don’t panic, go to Project→Build Options and choose your actual compiler from the listbox

  • make sure the "mingwRelease" target is selected

  • press Build

Current state

The generated statistics (specifically the numbers) aren’t entirely sane.
Testing on Debian and Windows with KiCad 5.1.6, 5.1.7, 5.1.9, 6.0.1, 6.0.5, 6.0.6, 7.0.6.

KiCad v6 added Exclude from BOM and Exclude from Board to components.
These attributes are not used for now. Exclude from BOM causes the component to not be written to the bom.xml at all, so there’s nothing that can be done here.


Usage

Command-line arguments:
  -c <cfg>          Config
  -R <fp2pkg>       Regex file for generating Package out of Footprint
  -d <path>         Sub-path for generating single BOM inside a project
  -o <filename>     Output filename for when merging multiple BOMs
  -Fhtml            Generate only .html
  -Fcsv             Generate only .csv

Examples

Single-BOM processing:
pimpmykicadbom [-d <subpath>] <bom1.xml> [count]

In Eeschema’s BOM plugin launcher, %I is replaced with the auto-generated .xml BOM filename.

The following example would cause pimpmykicadbom to generate the sub-directory /your_kicad_project/plots/bom (if it doesn’t exist), and generate output files in it, with a board count of 1:

pimpmykicadbom -d plots/bom %I

You can also use different configs:

pimpmykicadbom -c my_pmkb_config.xml -R my_fp2pkg.txt -d plots/bom %I

Example BOM.html

Multiple BOMs:
pimpmykicadbom -o <output_filename>
   <bom1.xml> <count>
   <bom2.xml> <count>
   [<bom3.xml> <count>]

The following command would generate final.csv and final.html in the current directory.

pimpmykicadbom -o final
    ~/kicad_projects/led_blinker/led_blinker.xml 20
    ~/kicad_projects/fancy_psu/fancy_psu.xml 24
    ~/kicad_projects/test_board/test_board.xml 4

Usually the .xml is in the project root directory, with the same name as the project folder.
In that case you can pass just the project root dir (make sure there’s a trailing slash).

Here’s a possibly shorter command line:

cd ~/kicad_projects/
pimpmykicadbom -o final led_blinker/ 20 fancy_psu/ 24 test_board/ 4
You can make "Diff" BOMs by "merging" two BOMs with <count> set to 1 and -1.
pimpmykicadbom -o my_diff basic_psu.xml -1 fancy_psu.xml 1

This would output my_diff.html and my_diff.csv, with the two BOMs merged (depending on the configuration).
The component quantities of the basic_psu would be multiplied by -1, so they’ll appear as negative.
"Same" components with the same quantities in both BOMs will thus "cancel out" to 0 (in the Total Quantity column).
Components that were removed from basic_psu would appear as negative quantities, while new components in fancy_psu would appear as positive quantities.


Config

The pimpmykicadbom.xml and fp2pkg_regex.txt config files are searched for with their default names in a few directories, including the user config dir. They can be specified with -c and -R respectively.
The user config dir (e.g. /home/user/.config/pimpmykicadbom/ on linux) is created, but default config files have to be manually placed there.

DoNotFit

<dnf> defines what will be used to indicate that a component should not be populated on the board, and thus it shouldn’t be counted in the BOM.
The name attribute sets the name of a Custom Field, and the text in the element sets the value that indicates "Do-Not-Fit".

    <dnf name="Config">dnf</dnf>

This would look for a custom field named "Config", and if it has a value of "dnf" then this component will be marked.

ColumnOrder

<column_order> defines the order of the columns in the output BOM. The <col> elements with name (like Ref, Value) are built-in.
You don’t have to delete them, turn them on/off with the used attribute.
You can re-arange them (select the whole line and cut+paste it to another position).
The <col> elements with custom (like Notes) are not built-in, they come from the symbol in Eeschema (Custom Fields), you can make any custom fields you want. The Notes entry is given as a default/example.

    <column_order>
        <col used="1" name  ="Ref"        />
        <col used="0" name  ="PV"         />
        <col used="1" name  ="Package"    />
        <col used="1" name  ="Value"      />
        <col used="0" name  ="Quantity"   />
        <col used="1" name  ="QTotal"     />
        <col used="1" name  ="Check"      />
        <col used="1" name  ="AllCustom"  />
        <col used="1" name  ="Description"/>
        <col used="1" name  ="Datasheet"  />
        <col used="1" name  ="SYMBOL"     />
        <col used="1" name  ="Footprint"  />
        <col used="1" name  ="SrcBOM"     />
        <col used="1" custom="Notes"      />
        <col used="0" name  ="ParsedVAL"  />
    </column_order>
Built-ins:
  • Ref - the annotated Reference (like C1, D5, R23, U6), this could be a list of references (after grouping).

  • Value - the component value (like 100nF, LM7805, 47k)

  • SYMBOL - the schematic Symbol and Library.

  • Footprint - the Footprint and Library.

  • Datasheet - the symbol Datasheet field.

  • Description - the symbol Description (it comes from the library).

  • Package - an auto-generated Package name, derived from the footprint name.

  • PV - a concattenation of the Package and Value

  • Quantity - the computed component count, for one board.

  • QTotal - the computed component count, for N boards.

  • Check - a CheckBox column in the HTML BOM

  • AllCustom - this entry would insert all unspecified custom fields that are found, at this position.

  • SrcBOM - which BOM does this component come from (useful in Merged BOMs).

  • ParsedVAL - the Parsed value out of the Value field

SortOrder

<sort_order> defines which component fields should be used (and in what order) for the sorting.
Otherwise they would be ordered in the way they are written in the input BOMs (and it’s usually semi-chaotic).

    <sort_order>
        <col used="1" name  ="DNF"        />
        <col used="0" name  ="Ref"        />
        <col used="1" name  ="RefDes"     />
        <col used="1" name  ="Package"    />
        <col used="1" name  ="ParsedVAL"  />
        <col used="1" name  ="Value"      />
        <col used="1" custom="Notes"      />
        <col used="0" name  ="Datasheet"  />
        <col used="0" name  ="Symbol"     />
        <col used="0" name  ="Description"/>
    </sort_order>
Built-ins:
  • RefDes - the non-annotated Reference (generated from the Ref by removing the digits from the end).

  • Symbol - the schematic Symbol name (without library).

  • DNF - the Do-Not-Fit attribute.

Tip
if you put DNF first, the Do-Not-Fit components will be written at the end of the BOM.
Tip
if you put RefDes first, the components will be sorted by their reference designator (AE, C, D, F, FB, J, K, L, …​)

Grouping

<group_by> defines which component fields are used for grouping.
Entries with used="1" tell that the values of this field must be the same for two components to be grouped.
All such fields must be the same between two components for them to get grouped.
Their Quantity is then summed.

    <group_by>
        <col used="1" name  ="DNF"        />
        <col used="1" name  ="Package"    />
        <col used="1" name  ="Value"      />
        <col used="1" name  ="ParsedVAL"  />
        <col used="0" name  ="RefDes"     />
        <col used="0" name  ="Footprint"  />
        <col used="0" name  ="FpLib"      />
        <col used="0" name  ="Symbol"     />
        <col used="0" name  ="SymLib"     />
        <col used="0" name  ="Datasheet"  />
        <col used="0" name  ="Description"/>
        <col used="0" custom="Notes"      />
    </group_by>
Built-ins:
  • SymLib - the symbol Library.

  • FpLib - the footprint Library.

Tip
If you’re using something like a "MPN" (manufacturer part number) or similar custom field, you’d want to use that here.

ColorInfluence

<color_influence> defines which fields have a bigger influence on the auto-generated pseudo-random row color in the HTML BOM.

    <color_influence>
        ...
    </color_influence>

OutputFileName

<output_name_format> defines the naming format for the output file.
This is for single-BOM processing.

    <output_name_format>%s-pmkb_%R-%D</output_name_format>

This would turn into something like MY_PROJECT-pmkb_REV1-DATE.html

Special symbols:
  • %n - the Name of the input BOM file

  • %s - the Name of the main schematic (.sch) sheet

  • %R - the Revision from the root schematic sheet

  • %D - the current date

SubPath

<output_subpath> sets a sub-directory for the output BOMs to be put in.
This is for single-BOM processing only.
If the path does not exist, it will be created.

Note
this can be specified (or overridden) by the -d commandline switch instead.
    <output_subpath>plots/bom</output_subpath>

Details

pimpmykicadbom uses a config file (in xml format, sorry).
The default one should contain all options such that you’d only change certain values if you want, or copy/paste lines, with minimum understanding of XML (i personally am allergic to XML).
There are comments in the config file describing the options.

The output files are .csv and .html.

  • CSV: Comma-Separated Values
    This is useful for importing into a spreadsheet program like LibreOffice Calc.
    Can be configured to use Tabs instead of Commas.

  • HTML:
    The column order is configurable.
    The information shown in the table is suppopsed to be short, boring details may be provided as tooltips.
    Datasheet values are turned into clickable Links with a short "Link" text.
    There’s a summary table with the project name, revision, date, board count, and then the actual BOM table, which is re-sortable and colorful.
    A CheckBox column can be generated, which can be useful when purchasing components, to mark that you’ve already bought a given component (note: the table is re-sortable).
    A quasi-random color is generated for each component via a dumb CRC32 or some other method, for fancyness.
    Do-Not-Fit is supported as text in a custom field.

Auto-generated Package field

Often i use a generic value scheme for dumb components like passives.
For resistors it might be like 10k or 100R or 4.99k, etc.
For capacitors 100n, 10u/16, etc..

Additionally i would have a Custom Field "BOMComment", or "Notes", where i’d write additional info like "X7R" or "1%" or "Alt: \<some alternative components\>", and i’d want to see this field in the BOM.

One problem is that i have same value components accross projects (like the 10k resistor), but sometimes it may be THT, other times SMD (different sizes).
It can be useful to prepend the footprint name to the value for sorting and grouping, but unfortunately i often use the HandSoldering variants which have quite long names, with extra details that don’t matter when you’re looking at a BOM with the task of ordering components.

For example:

C_0603_1608Metric_Pad1.05x0.95mm_HandSolder
C_0805_2012Metric_Pad1.15x1.40mm_HandSolder
C_1206_3216Metric_Pad1.42x1.75mm_HandSolder
D_0805_2012Metric_Pad1.15x1.40mm_HandSolder
LED_0805_2012Metric_Pad1.15x1.40mm_HandSolder
L_0805_2012Metric_Pad1.15x1.40mm_HandSolder
R_0603_1608Metric_Pad1.05x0.95mm_HandSolder
…​

If the footprint name is used for the component grouping, then the following won’t be grouped, even tho they should be the same component (if the value is the same):

R_0603_1608Metric
R_0603_1608Metric_Pad1.05x0.95mm_HandSolder

LED_0805_2012Metric_Pad1.15x1.40mm_HandSolder
LED_0805_2012Metric_Castellated
LED_0805_2012Metric

TO-92
TO-92_Wide
TO-92_HandSolder
TO-92_Inline
TO-92_Inline_Horizontal1
TO-92_Inline_Horizontal2
TO-92_Inline_Wide
TO-92_Horizontal1
TO-92_Horizontal2

Thus, pimpmykicadbom tries to auto-generate a "Package" field that should be more useful for grouping and sorting purpose than the footprint name.
This is done with std::regex, and an external file that contains the instructions, processing the footprint name to simplify it and remove some boring details.
The original footprint and library name are available as a tooltip.

The contents of the regex file should be formatted like:

s/SEARCH_STRING/REPLACE_STRING

fp2pkg example instructions:
s/^(CP_Radial_)/CP_
s/(.+)(_HandSoldering|_HandSolder)/$1

This should rename CP_Radial_* to just CP_* and remove the "_HandSoldering" from the end of footprints

The default config file should be set up to group and sort components by Package+Value mainly, then "similar" components, if they don’t get grouped should be listed close together.

Parsed Value

pimpmykicadbom tries to parse the component Value field for "passive" components, to get a "normalized" value and then tries to make an "optimized" version of the value.

Table 1. Example:
Value Normalized Optimized

"10k"

10000

"10k"

"49R9"

49.9

"49.9"

"4k99"

4990

"4.99k"

"6800Ω"

6800

"6.8kΩ"

"4700m"

4.7

"4.7"

"0.1u/50 5%"

0.0000001

"100n/50 5%"

".1μ"

0.0000001

"100n"

"100n0"

0.0000001

"100n"

"2200.0nF"

0.0000022

"2.2μF"

Supported unit prefixes:

femto

pico

nano

micro

micro

milli

kilo

Mega

Giga

f

p

n

u

μ

m

k

M

G

Supported Components (detected via RefDes):
RefDes Units

R, RV, RN, RT

resistance (R, Ω)

C

capacitance (F)

L, FB

inductance (H)

Y

frequency (Hz)

This can be useful for sorting the passive components in the BOM.


TODO:

  • Try to not show local paths and filenames in the generated BOMs (people’s usernames and such)

  • it’d be great if someone with HTML knowlage gives some advice

  • maybe many of the hard-coded HTML stuff can be moved to an external file somehow, so that it can be edited by the user?

  • it’d be great if someone with regex skillz checks the fp2pkg instructions, or adds better ones

  • would anyone want to merge BOMs which were processed with different configs? (allow multiple -c and -R flags)

  • could it be useful to have a mechanism for fractional quantities (e.g. for choppable pin header connectors)?


Last updated: 2023-09-07