From 49ea1bb62adc6a89d4eaab1ae18387f1c9902572 Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Mon, 22 Nov 2021 14:34:07 -0300 Subject: [PATCH] Internal BoM: `count_smd_tht` option to compute SMD/THT stats. Closes #113 --- CHANGELOG.md | 1 + README.md | 1 + docs/samples/generic_plot.kibot.yaml | 2 + kibot/bom/bom.py | 44 ++- kibot/bom/csv_writer.py | 12 +- kibot/bom/html_writer.py | 12 +- kibot/bom/xlsx_writer.py | 12 +- kibot/bom/xml_writer.py | 8 +- kibot/misc.py | 1 + kibot/out_bom.py | 7 +- tests/board_samples/kicad_5/links.kicad_pcb | 282 ++++++++++++++++++ tests/board_samples/kicad_5/links.sch | 8 +- tests/test_plot/test_int_bom.py | 3 + .../int_bom_column_rename_csv.kibot.yaml | 1 + .../int_bom_column_rename_xlsx.kibot.yaml | 1 + .../int_bom_column_rename_xml.kibot.yaml | 1 + .../int_bom_datasheet_link.kibot.yaml | 1 + 17 files changed, 366 insertions(+), 31 deletions(-) create mode 100644 tests/board_samples/kicad_5/links.kicad_pcb diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d7a5c28..a7a28dd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Internal BoM: when a `Value` field can't be interpreted as a `number+unit`, and it contain at least one space, now we try to use the text before the space. This helps for cases like "10K 1%". +- Internal BoM: `count_smd_tht` option to compute SMD/THT stats. (#113) - Generic filter: options to match if a field is/isn't defined. - Excellon drill: added `route_mode_for_oval_holes` option. - Default global `dir` option. diff --git a/README.md b/README.md index 1c79474a..28267a0d 100644 --- a/README.md +++ b/README.md @@ -689,6 +689,7 @@ Next time you need this list just use an alias, like this: - `join`: [list(string)|string=''] List of fields to join to this column. - `level`: [number=0] Used to group columns. The XLSX output uses it to collapse columns. - `name`: [string=''] Name to display in the header. The field is used when empty. + - `count_smd_tht`: [boolean=false] Show the stats about how many of the components are SMD/THT. You must provide the PCB. - `csv`: [dict] Options for the CSV, TXT and TSV formats. * Valid keys: - `hide_pcb_info`: [boolean=false] Hide project information. diff --git a/docs/samples/generic_plot.kibot.yaml b/docs/samples/generic_plot.kibot.yaml index 72fcaad0..74d6da0f 100644 --- a/docs/samples/generic_plot.kibot.yaml +++ b/docs/samples/generic_plot.kibot.yaml @@ -99,6 +99,8 @@ outputs: level: 0 # [string=''] Name to display in the header. The field is used when empty name: 'Line' + # [boolean=false] Show the stats about how many of the components are SMD/THT. You must provide the PCB + count_smd_tht: false # [dict] Options for the CSV, TXT and TSV formats csv: # [boolean=false] Hide project information diff --git a/kibot/bom/bom.py b/kibot/bom/bom.py index bddaaa80..f33e9ada 100644 --- a/kibot/bom/bom.py +++ b/kibot/bom/bom.py @@ -244,6 +244,12 @@ class ComponentGroup(object): # compare_components ensures all has the same status return self.components[0].fixed + def is_smd(self): + return self.components[0].smd + + def is_tht(self): + return self.components[0].tht + def get_field(self, field): field = field.lower() if field not in self.fields or not self.fields[field]: @@ -378,8 +384,8 @@ def normalize_value(c, decimal_point): def compute_multiple_stats(cfg, groups): for sch in cfg.aggregate: - sch.comp_total = 0 - sch.comp_fitted = 0 + sch.comp_total = sch.comp_total_smd = sch.comp_total_tht = 0 + sch.comp_fitted = sch.comp_fitted_smd = sch.comp_fitted_tht = 0 sch.comp_build = 0 sch.comp_groups = 0 for g in groups: @@ -387,8 +393,16 @@ def compute_multiple_stats(cfg, groups): if g_l: sch.comp_groups = sch.comp_groups+1 sch.comp_total += g_l + if g.is_smd(): + sch.comp_total_smd += g_l + if g.is_tht(): + sch.comp_total_tht += g_l if g.is_fitted(): sch.comp_fitted += g_l + if g.is_smd(): + sch.comp_fitted_smd += g_l + if g.is_tht(): + sch.comp_fitted_tht += g_l sch.comp_build = sch.comp_fitted*sch.number if cfg.debug_level > 1: logger.debug('Stats for {}: total {} fitted {} build {}'. @@ -442,8 +456,8 @@ def group_components(cfg, components): # First priority is the Type of component (e.g. R?, U?, L?) groups = sorted(groups, key=lambda g: [g.components[0].ref_prefix, get_value_sort(g.components[0])]) # Enumerate the groups and compute stats - n_total = 0 - n_fitted = 0 + n_total = n_total_smd = n_total_tht = 0 + n_fitted = n_fitted_smd = n_fitted_tht = 0 n_build = 0 c = 1 dnf = 1 @@ -459,11 +473,19 @@ def group_components(cfg, components): # Stats g_l = g.get_count() n_total += g_l + n_total_smd += g_l*g.is_smd() + n_total_tht += g_l*g.is_tht() if is_fitted: n_fitted += g_l + n_fitted_smd += g_l*g.is_smd() + n_fitted_tht += g_l*g.is_tht() n_build += g.total cfg.n_total = n_total + cfg.n_total_smd = n_total_smd + cfg.n_total_tht = n_total_tht cfg.n_fitted = n_fitted + cfg.n_fitted_smd = n_fitted_smd + cfg.n_fitted_tht = n_fitted_tht cfg.n_build = n_build if cfg.debug_level > 1: logger.debug('Global stats: total {} fitted {} build {}'.format(n_total, n_fitted, n_build)) @@ -473,6 +495,12 @@ def group_components(cfg, components): return groups +def smd_tht(cfg, tot, smd, tht): + if cfg.count_smd_tht: + return "{} ({} SMD/ {} THT)".format(tot, smd, tht) + return tot + + def do_bom(file_name, ext, comps, cfg): # Group components according to group_fields groups = group_components(cfg, comps) @@ -480,5 +508,13 @@ def do_bom(file_name, ext, comps, cfg): logger.debug("Saving BOM File: "+file_name) number = cfg.number cfg.number = sum(map(lambda prj: prj.number, cfg.aggregate)) + # Pre-format the total and fitted strings + cfg.total_str = smd_tht(cfg, cfg.n_total, cfg.n_total_smd, cfg.n_total_tht) + cfg.fitted_str = smd_tht(cfg, cfg.n_fitted, cfg.n_fitted_smd, cfg.n_fitted_tht) + if len(cfg.aggregate) > 1: + for prj in cfg.aggregate: + prj.total_str = smd_tht(cfg, prj.comp_total, prj.comp_total_smd, prj.comp_total_tht) + prj.fitted_str = smd_tht(cfg, prj.comp_fitted, prj.comp_fitted_smd, prj.comp_fitted_tht) + # Create the BoM write_bom(file_name, ext, groups, cfg.columns, cfg) cfg.number = number diff --git a/kibot/bom/csv_writer.py b/kibot/bom/csv_writer.py index e1976b12..7fb05740 100644 --- a/kibot/bom/csv_writer.py +++ b/kibot/bom/csv_writer.py @@ -25,8 +25,8 @@ def write_stats(writer, cfg): if not cfg.csv.hide_stats_info: writer.writerow(["Statistics:"]) writer.writerow(["Component Groups:", cfg.n_groups]) - writer.writerow(["Component Count:", cfg.n_total]) - writer.writerow(["Fitted Components:", cfg.n_fitted]) + writer.writerow(["Component Count:", cfg.total_str]) + writer.writerow(["Fitted Components:", cfg.fitted_str]) writer.writerow(["Number of PCBs:", cfg.number]) writer.writerow(["Total Components:", cfg.n_build]) else: @@ -39,8 +39,8 @@ def write_stats(writer, cfg): if not cfg.csv.hide_stats_info: writer.writerow(["Global statistics:"]) writer.writerow(["Component Groups:", cfg.n_groups]) - writer.writerow(["Component Count:", cfg.n_total]) - writer.writerow(["Fitted Components:", cfg.n_fitted]) + writer.writerow(["Component Count:", cfg.total_str]) + writer.writerow(["Fitted Components:", cfg.fitted_str]) writer.writerow(["Number of PCBs:", cfg.number]) writer.writerow(["Total Components:", cfg.n_build]) # Individual stats @@ -57,8 +57,8 @@ def write_stats(writer, cfg): if not cfg.csv.hide_stats_info: writer.writerow(["Statistics:", prj.sch.title]) writer.writerow(["Component Groups:", prj.comp_groups]) - writer.writerow(["Component Count:", prj.comp_total]) - writer.writerow(["Fitted Components:", prj.comp_fitted]) + writer.writerow(["Component Count:", prj.total_str]) + writer.writerow(["Fitted Components:", prj.fitted_str]) writer.writerow(["Number of PCBs:", prj.number]) writer.writerow(["Total Components:", prj.comp_build]) diff --git a/kibot/bom/html_writer.py b/kibot/bom/html_writer.py index 2a9857c5..d4d92ea0 100644 --- a/kibot/bom/html_writer.py +++ b/kibot/bom/html_writer.py @@ -291,8 +291,8 @@ def write_stats(html, cfg): html.write(' \n') if not cfg.html.hide_stats_info: html.write(" Component Groups: {}
\n".format(cfg.n_groups)) - html.write(" Component Count: {} (per PCB)
\n\n".format(cfg.n_total)) - html.write(" Fitted Components: {} (per PCB)
\n".format(cfg.n_fitted)) + html.write(" Component Count: {} (per PCB)
\n\n".format(cfg.total_str)) + html.write(" Fitted Components: {} (per PCB)
\n".format(cfg.fitted_str)) html.write(" Number of PCBs: {}
\n".format(cfg.number)) html.write(" Total Components: {t} (for {n} PCBs)
\n".format(n=cfg.number, t=cfg.n_build)) html.write(' \n') @@ -309,8 +309,8 @@ def write_stats(html, cfg): html.write(' \n') if not cfg.html.hide_stats_info: html.write(" Component Groups: {}
\n".format(cfg.n_groups)) - html.write(" Component Count: {} (per PCB)
\n\n".format(cfg.n_total)) - html.write(" Fitted Components: {} (per PCB)
\n".format(cfg.n_fitted)) + html.write(" Component Count: {} (per PCB)
\n\n".format(cfg.total_str)) + html.write(" Fitted Components: {} (per PCB)
\n".format(cfg.fitted_str)) html.write(" Number of PCBs: {}
\n".format(cfg.number)) html.write(" Total Components: {t} (for {n} PCBs)
\n".format(n=cfg.number, t=cfg.n_build)) html.write(' \n') @@ -336,8 +336,8 @@ def write_stats(html, cfg): html.write(' \n') if not cfg.html.hide_stats_info: html.write(" Component Groups: {}
\n".format(prj.comp_groups)) - html.write(" Component Count: {} (per PCB)
\n\n".format(prj.comp_total)) - html.write(" Fitted Components: {} (per PCB)
\n".format(prj.comp_fitted)) + html.write(" Component Count: {} (per PCB)
\n\n".format(prj.total_str)) + html.write(" Fitted Components: {} (per PCB)
\n".format(prj.fitted_str)) html.write(" Number of PCBs: {}
\n".format(prj.number)) html.write(" Total Components: {t} (for {n} PCBs)
\n".format(n=prj.number, t=prj.comp_build)) html.write(' \n') diff --git a/kibot/bom/xlsx_writer.py b/kibot/bom/xlsx_writer.py index dfd58f40..6c6612af 100644 --- a/kibot/bom/xlsx_writer.py +++ b/kibot/bom/xlsx_writer.py @@ -281,8 +281,8 @@ def write_info(cfg, r_info_start, worksheet, column_widths, col1, fmt_info, fmt_ rc = r_info_start if not cfg.xlsx.hide_stats_info: rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Groups:", cfg.n_groups) - rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Count:", cfg.n_total) - rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Fitted Components:", cfg.n_fitted) + rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Count:", cfg.total_str) + rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Fitted Components:", cfg.fitted_str) rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Number of PCBs:", cfg.number) rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Total Components:", cfg.n_build) else: @@ -297,8 +297,8 @@ def write_info(cfg, r_info_start, worksheet, column_widths, col1, fmt_info, fmt_ rc = r_info_start if not cfg.xlsx.hide_stats_info: rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Groups:", cfg.n_groups) - rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Count:", cfg.n_total) - rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Fitted Components:", cfg.n_fitted) + rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Count:", cfg.total_str) + rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Fitted Components:", cfg.fitted_str) rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Number of PCBs:", cfg.number) rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Total Components:", cfg.n_build) # Individual stats @@ -322,8 +322,8 @@ def write_info(cfg, r_info_start, worksheet, column_widths, col1, fmt_info, fmt_ rc = r_info_start if not cfg.xlsx.hide_stats_info: rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Groups:", prj.comp_groups) - rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Count:", prj.comp_total) - rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Fitted Components:", prj.comp_fitted) + rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Component Count:", prj.total_str) + rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Fitted Components:", prj.fitted_str) rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Number of PCBs:", prj.number) rc = add_info(worksheet, column_widths, rc, col1, fmt_info, "Total Components:", prj.comp_build) r_info_start += 5 diff --git a/kibot/bom/xml_writer.py b/kibot/bom/xml_writer.py index 869ad582..0cdca0de 100644 --- a/kibot/bom/xml_writer.py +++ b/kibot/bom/xml_writer.py @@ -26,8 +26,8 @@ def write_xml(filename, groups, headings, head_names, cfg): attrib['PCB_Variant'] = cfg.variant.name attrib['KiCad_Version'] = cfg.kicad_version attrib['Component_Groups'] = str(cfg.n_groups) - attrib['Component_Count'] = str(cfg.n_total) - attrib['Fitted_Components'] = str(cfg.n_fitted) + attrib['Component_Count'] = str(cfg.total_str) + attrib['Fitted_Components'] = str(cfg.fitted_str) attrib['Number_of_PCBs'] = str(cfg.number) attrib['Total_Components'] = str(cfg.n_build) if len(cfg.aggregate) == 1: @@ -42,8 +42,8 @@ def write_xml(filename, groups, headings, head_names, cfg): attrib['Schematic{}_Date'.format(n)] = prj.sch.date attrib['Schematic{}_ID'.format(n)] = prj.ref_id attrib['Component_Groups{}'.format(n)] = str(prj.comp_groups) - attrib['Component_Count{}'.format(n)] = str(prj.comp_total) - attrib['Fitted_Components{}'.format(n)] = str(prj.comp_fitted) + attrib['Component_Count{}'.format(n)] = str(prj.total_str) + attrib['Fitted_Components{}'.format(n)] = str(prj.fitted_str) attrib['Number_of_PCBs{}'.format(n)] = str(prj.number) attrib['Total_Components{}'.format(n)] = str(prj.comp_build) xml = ElementTree.Element('KiCad_BOM', attrib=attrib, encoding='utf-8') diff --git a/kibot/misc.py b/kibot/misc.py index 0426656c..d231c674 100644 --- a/kibot/misc.py +++ b/kibot/misc.py @@ -206,6 +206,7 @@ W_UNKOUT = '(W067) ' W_NOFILTERS = '(W068) ' W_NOVARIANTS = '(W069) ' W_NOENDLIB = '(W070) ' +W_NEEDSPCB = '(W071) ' class Rect(object): diff --git a/kibot/out_bom.py b/kibot/out_bom.py index 8ea1d691..66d0ce2e 100644 --- a/kibot/out_bom.py +++ b/kibot/out_bom.py @@ -9,7 +9,7 @@ This is somehow compatible with KiBoM. """ import os from .gs import GS -from .misc import W_BADFIELD +from .misc import W_BADFIELD, W_NEEDSPCB from .optionable import Optionable, BaseOptions from .registrable import RegOutput from .error import KiPlotConfigurationError @@ -309,6 +309,8 @@ class BoMOptions(BaseOptions): """ [string|list(string)] Include this distributors list. Default is all the available """ self.no_distributors = Optionable """ [string|list(string)] Exclude this distributors list. They are removed after computing `distributors` """ + self.count_smd_tht = False + """ Show the stats about how many of the components are SMD/THT. You must provide the PCB """ self._format_example = 'CSV' super().__init__() @@ -509,6 +511,9 @@ class BoMOptions(BaseOptions): # Get the components list from the schematic comps = GS.sch.get_components() get_board_comps_data(comps) + if self.count_smd_tht and not GS.pcb_file: + logger.warning(W_NEEDSPCB+"`count_smd_tht` is enabled, but no PCB provided") + self.count_smd_tht = False # Apply the reference prefix for c in comps: c.ref = self.ref_id+c.ref diff --git a/tests/board_samples/kicad_5/links.kicad_pcb b/tests/board_samples/kicad_5/links.kicad_pcb new file mode 100644 index 00000000..18588075 --- /dev/null +++ b/tests/board_samples/kicad_5/links.kicad_pcb @@ -0,0 +1,282 @@ +(kicad_pcb (version 20171130) (host pcbnew 5.1.9+dfsg1-1) + + (general + (thickness 1.6) + (drawings 4) + (tracks 15) + (zones 0) + (modules 4) + (nets 4) + ) + + (page A4) + (layers + (0 F.Cu signal) + (31 B.Cu signal) + (32 B.Adhes user) + (33 F.Adhes user) + (34 B.Paste user) + (35 F.Paste user) + (36 B.SilkS user) + (37 F.SilkS user) + (38 B.Mask user) + (39 F.Mask user) + (40 Dwgs.User user) + (41 Cmts.User user) + (42 Eco1.User user) + (43 Eco2.User user) + (44 Edge.Cuts user) + (45 Margin user) + (46 B.CrtYd user) + (47 F.CrtYd user) + (48 B.Fab user) + (49 F.Fab user) + ) + + (setup + (last_trace_width 0.25) + (trace_clearance 0.2) + (zone_clearance 0.508) + (zone_45_only no) + (trace_min 0.2) + (via_size 0.8) + (via_drill 0.4) + (via_min_size 0.4) + (via_min_drill 0.3) + (uvia_size 0.3) + (uvia_drill 0.1) + (uvias_allowed no) + (uvia_min_size 0.2) + (uvia_min_drill 0.1) + (edge_width 0.1) + (segment_width 0.2) + (pcb_text_width 0.3) + (pcb_text_size 1.5 1.5) + (mod_edge_width 0.15) + (mod_text_size 1 1) + (mod_text_width 0.15) + (pad_size 1.524 1.524) + (pad_drill 0.762) + (pad_to_mask_clearance 0) + (aux_axis_origin 0 0) + (visible_elements FFFFFF7F) + (pcbplotparams + (layerselection 0x010fc_ffffffff) + (usegerberextensions false) + (usegerberattributes true) + (usegerberadvancedattributes true) + (creategerberjobfile true) + (excludeedgelayer true) + (linewidth 0.100000) + (plotframeref false) + (viasonmask false) + (mode 1) + (useauxorigin false) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (psnegative false) + (psa4output false) + (plotreference true) + (plotvalue true) + (plotinvisibletext false) + (padsonsilk false) + (subtractmaskfromsilk false) + (outputformat 1) + (mirror false) + (drillshape 1) + (scaleselection 1) + (outputdirectory "")) + ) + + (net 0 "") + (net 1 "Net-(C1-Pad2)") + (net 2 "Net-(C1-Pad1)") + (net 3 "Net-(J1-Pad1)") + + (net_class Default "Esta es la clase de red por defecto." + (clearance 0.2) + (trace_width 0.25) + (via_dia 0.8) + (via_drill 0.4) + (uvia_dia 0.3) + (uvia_drill 0.1) + (add_net "Net-(C1-Pad1)") + (add_net "Net-(C1-Pad2)") + (add_net "Net-(J1-Pad1)") + ) + + (module Resistor_SMD:R_0805_2012Metric (layer F.Cu) (tedit 5F68FEEE) (tstamp 619BCC07) + (at 137.9909 96.11672) + (descr "Resistor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 72, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf), generated with kicad-footprint-generator") + (tags resistor) + (path /5F10F746) + (attr smd) + (fp_text reference R1 (at 0 -1.65) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value 1k (at 0 1.65) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_line (start 1.68 0.95) (end -1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.68 -0.95) (end 1.68 0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 -0.95) (end 1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.68 0.95) (end -1.68 -0.95) (layer F.CrtYd) (width 0.05)) + (fp_line (start -0.227064 0.735) (end 0.227064 0.735) (layer F.SilkS) (width 0.12)) + (fp_line (start -0.227064 -0.735) (end 0.227064 -0.735) (layer F.SilkS) (width 0.12)) + (fp_line (start 1 0.625) (end -1 0.625) (layer F.Fab) (width 0.1)) + (fp_line (start 1 -0.625) (end 1 0.625) (layer F.Fab) (width 0.1)) + (fp_line (start -1 -0.625) (end 1 -0.625) (layer F.Fab) (width 0.1)) + (fp_line (start -1 0.625) (end -1 -0.625) (layer F.Fab) (width 0.1)) + (fp_text user %R (at 0 0) (layer F.Fab) + (effects (font (size 0.5 0.5) (thickness 0.08))) + ) + (pad 1 smd roundrect (at -0.9125 0) (size 1.025 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.243902) + (net 2 "Net-(C1-Pad1)")) + (pad 2 smd roundrect (at 0.9125 0) (size 1.025 1.4) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.243902) + (net 3 "Net-(J1-Pad1)")) + (model ${KISYS3DMOD}/Resistor_SMD.3dshapes/R_0805_2012Metric.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical (layer F.Cu) (tedit 59FED5CC) (tstamp 619BCBF6) + (at 133.4609 93.95672) + (descr "Through hole straight pin header, 1x02, 2.54mm pitch, single row") + (tags "Through hole pin header THT 1x02 2.54mm single row") + (path /5F10E81F) + (fp_text reference J2 (at 0 -2.33) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value "Molex KK" (at 0 4.87) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_line (start 1.8 -1.8) (end -1.8 -1.8) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.8 4.35) (end 1.8 -1.8) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.8 4.35) (end 1.8 4.35) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.8 -1.8) (end -1.8 4.35) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.33 -1.33) (end 0 -1.33) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 0) (end -1.33 -1.33) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 1.27) (end 1.33 1.27) (layer F.SilkS) (width 0.12)) + (fp_line (start 1.33 1.27) (end 1.33 3.87) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 1.27) (end -1.33 3.87) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 3.87) (end 1.33 3.87) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.27 -0.635) (end -0.635 -1.27) (layer F.Fab) (width 0.1)) + (fp_line (start -1.27 3.81) (end -1.27 -0.635) (layer F.Fab) (width 0.1)) + (fp_line (start 1.27 3.81) (end -1.27 3.81) (layer F.Fab) (width 0.1)) + (fp_line (start 1.27 -1.27) (end 1.27 3.81) (layer F.Fab) (width 0.1)) + (fp_line (start -0.635 -1.27) (end 1.27 -1.27) (layer F.Fab) (width 0.1)) + (fp_text user %R (at 0 1.27 90) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 1 thru_hole rect (at 0 0) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) + (net 2 "Net-(C1-Pad1)")) + (pad 2 thru_hole oval (at 0 2.54) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) + (net 1 "Net-(C1-Pad2)")) + (model ${KISYS3DMOD}/Connector_PinHeader_2.54mm.3dshapes/PinHeader_1x02_P2.54mm_Vertical.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical (layer F.Cu) (tedit 59FED5CC) (tstamp 619BCCDC) + (at 142.80388 96.47174 180) + (descr "Through hole straight pin header, 1x02, 2.54mm pitch, single row") + (tags "Through hole pin header THT 1x02 2.54mm single row") + (path /5F10E435) + (fp_text reference J1 (at 0 -2.33) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value "Molex KK ñoño" (at 0 4.87) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_line (start 1.8 -1.8) (end -1.8 -1.8) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.8 4.35) (end 1.8 -1.8) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.8 4.35) (end 1.8 4.35) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.8 -1.8) (end -1.8 4.35) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.33 -1.33) (end 0 -1.33) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 0) (end -1.33 -1.33) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 1.27) (end 1.33 1.27) (layer F.SilkS) (width 0.12)) + (fp_line (start 1.33 1.27) (end 1.33 3.87) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 1.27) (end -1.33 3.87) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.33 3.87) (end 1.33 3.87) (layer F.SilkS) (width 0.12)) + (fp_line (start -1.27 -0.635) (end -0.635 -1.27) (layer F.Fab) (width 0.1)) + (fp_line (start -1.27 3.81) (end -1.27 -0.635) (layer F.Fab) (width 0.1)) + (fp_line (start 1.27 3.81) (end -1.27 3.81) (layer F.Fab) (width 0.1)) + (fp_line (start 1.27 -1.27) (end 1.27 3.81) (layer F.Fab) (width 0.1)) + (fp_line (start -0.635 -1.27) (end 1.27 -1.27) (layer F.Fab) (width 0.1)) + (fp_text user %R (at 0 1.27 90) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 1 thru_hole rect (at 0 0 180) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) + (net 3 "Net-(J1-Pad1)")) + (pad 2 thru_hole oval (at 0 2.54 180) (size 1.7 1.7) (drill 1) (layers *.Cu *.Mask) + (net 1 "Net-(C1-Pad2)")) + (model ${KISYS3DMOD}/Connector_PinHeader_2.54mm.3dshapes/PinHeader_1x02_P2.54mm_Vertical.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module Capacitor_SMD:C_0805_2012Metric (layer F.Cu) (tedit 5F68FEEE) (tstamp 619BCBCA) + (at 138 93) + (descr "Capacitor SMD 0805 (2012 Metric), square (rectangular) end terminal, IPC_7351 nominal, (Body size source: IPC-SM-782 page 76, https://www.pcb-3d.com/wordpress/wp-content/uploads/ipc-sm-782a_amendment_1_and_2.pdf, https://docs.google.com/spreadsheets/d/1BsfQQcO9C6DZCsRaXUlFlo91Tg2WpOkGARC1WS5S8t0/edit?usp=sharing), generated with kicad-footprint-generator") + (tags capacitor) + (path /5F10F92F) + (attr smd) + (fp_text reference C1 (at 0 -1.68) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value 1nF (at 0 1.68) (layer F.Fab) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_line (start 1.7 0.98) (end -1.7 0.98) (layer F.CrtYd) (width 0.05)) + (fp_line (start 1.7 -0.98) (end 1.7 0.98) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.7 -0.98) (end 1.7 -0.98) (layer F.CrtYd) (width 0.05)) + (fp_line (start -1.7 0.98) (end -1.7 -0.98) (layer F.CrtYd) (width 0.05)) + (fp_line (start -0.261252 0.735) (end 0.261252 0.735) (layer F.SilkS) (width 0.12)) + (fp_line (start -0.261252 -0.735) (end 0.261252 -0.735) (layer F.SilkS) (width 0.12)) + (fp_line (start 1 0.625) (end -1 0.625) (layer F.Fab) (width 0.1)) + (fp_line (start 1 -0.625) (end 1 0.625) (layer F.Fab) (width 0.1)) + (fp_line (start -1 -0.625) (end 1 -0.625) (layer F.Fab) (width 0.1)) + (fp_line (start -1 0.625) (end -1 -0.625) (layer F.Fab) (width 0.1)) + (fp_text user %R (at 0 0) (layer F.Fab) + (effects (font (size 0.5 0.5) (thickness 0.08))) + ) + (pad 1 smd roundrect (at -0.95 0) (size 1 1.45) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) + (net 2 "Net-(C1-Pad1)")) + (pad 2 smd roundrect (at 0.95 0) (size 1 1.45) (layers F.Cu F.Paste F.Mask) (roundrect_rratio 0.25) + (net 1 "Net-(C1-Pad2)")) + (model ${KISYS3DMOD}/Capacitor_SMD.3dshapes/C_0805_2012Metric.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (gr_line (start 131 100) (end 131 91) (layer Edge.Cuts) (width 0.1) (tstamp 619BCF98)) + (gr_line (start 146 100) (end 131 100) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 146 91) (end 146 100) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 131 91) (end 146 91) (layer Edge.Cuts) (width 0.1)) + + (segment (start 133.4609 96.49672) (end 133.49672 96.49672) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 133.49672 96.49672) (end 136 99) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 136 99) (end 144 99) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 144 99) (end 145 98) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 145 98) (end 145 95) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 143.93174 93.93174) (end 142.80388 93.93174) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 145 95) (end 143.93174 93.93174) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 142.80388 93.93174) (end 139.93174 93.93174) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 139.93174 93.93174) (end 139 93) (width 0.25) (layer B.Cu) (net 1)) + (segment (start 133.4609 93.95672) (end 135.04328 93.95672) (width 0.25) (layer B.Cu) (net 2)) + (segment (start 135.04328 93.95672) (end 136 93) (width 0.25) (layer B.Cu) (net 2)) + (segment (start 136 93) (end 137 93) (width 0.25) (layer B.Cu) (net 2)) + (segment (start 137 93) (end 137 96) (width 0.25) (layer B.Cu) (net 2)) + (segment (start 142.80388 96.47174) (end 139.47174 96.47174) (width 0.25) (layer B.Cu) (net 3)) + (segment (start 139.47174 96.47174) (end 139 96) (width 0.25) (layer B.Cu) (net 3)) + +) diff --git a/tests/board_samples/kicad_5/links.sch b/tests/board_samples/kicad_5/links.sch index d53724fd..dceba400 100644 --- a/tests/board_samples/kicad_5/links.sch +++ b/tests/board_samples/kicad_5/links.sch @@ -21,7 +21,7 @@ U 1 1 5F10E435 P 2850 2300 F 0 "J1" H 2750 2200 50 0000 C CNN F 1 "Molex KK ñoño" H 2850 2100 50 0000 C CNN -F 2 "" H 2850 2300 50 0001 C CNN +F 2 "Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical" H 2850 2300 50 0001 C CNN F 3 "https://www.molex.com/webdocs/datasheets/pdf/en-us//0022232021_PCB_HEADERS.pdf" H 2850 2300 50 0001 C CNN F 4 "900-0022232021-ND" H 2850 2300 50 0001 C CNN "digikey#" F 5 "0022232021" H 2850 2300 50 0001 C CNN "manf#" @@ -35,7 +35,7 @@ U 1 1 5F10E81F P 4500 2300 F 0 "J2" H 4450 2200 50 0000 R CNN F 1 "Molex KK" H 4700 2100 50 0000 R CNN -F 2 "" H 4500 2300 50 0001 C CNN +F 2 "Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_Vertical" H 4500 2300 50 0001 C CNN F 3 "https://www.molex.com/webdocs/datasheets/pdf/en-us//0022232021_PCB_HEADERS.pdf" H 4500 2300 50 0001 C CNN F 4 "900-0022232021-ND" H 4500 2300 50 0001 C CNN "digikey#" F 5 "0022232021" H 4500 2300 50 0001 C CNN "manf#" @@ -49,7 +49,7 @@ U 1 1 5F10F746 P 3450 2300 F 0 "R1" V 3350 2300 50 0000 C CNN F 1 "1k" V 3450 2300 50 0000 C CNN -F 2 "" V 3380 2300 50 0001 C CNN +F 2 "Resistor_SMD:R_0805_2012Metric" V 3380 2300 50 0001 C CNN F 3 "https://www.bourns.com/docs/product-datasheets/CRxxxxx.pdf" H 3450 2300 50 0001 C CNN F 4 "CR0805-JW-102ELFCT-ND" V 3450 2300 50 0001 C CNN "digikey#" F 5 "CR0805-JW-102ELF" V 3450 2300 50 0001 C CNN "manf#" @@ -63,7 +63,7 @@ U 1 1 5F10F92F P 3750 2500 F 0 "C1" H 3865 2546 50 0000 L CNN F 1 "1nF" H 3865 2455 50 0000 L CNN -F 2 "" H 3788 2350 50 0001 C CNN +F 2 "Capacitor_SMD:C_0805_2012Metric" H 3788 2350 50 0001 C CNN F 3 "https://content.kemet.com/datasheets/KEM_C1002_X7R_SMD.pdf" H 3750 2500 50 0001 C CNN F 4 "399-1147-1-ND" H 3750 2500 50 0001 C CNN "digikey#" F 5 "C0805C102K5RACTU" H 3750 2500 50 0001 C CNN "manf#" diff --git a/tests/test_plot/test_int_bom.py b/tests/test_plot/test_int_bom.py index 87054cf3..db3692bb 100644 --- a/tests/test_plot/test_int_bom.py +++ b/tests/test_plot/test_int_bom.py @@ -86,11 +86,13 @@ KIBOM_TEST_COMPONENTS_ALT2 = ['C1-C4', 'R9', 'R10', 'R7', 'R8', 'R1', 'R2', 'R4' KIBOM_TEST_EXCLUDE = ['R6'] KIBOM_TEST_GROUPS = 5 KIBOM_PRJ_INFO = ['kibom-test', 'default', 'A', '2020-03-12', None] +LINKS_PRJ_INFO = ['links', 'default', 'A', '2020-03-12', None] KIBOM_STATS = [KIBOM_TEST_GROUPS+len(KIBOM_TEST_EXCLUDE), len(KIBOM_TEST_COMPONENTS)+len(KIBOM_TEST_EXCLUDE), len(KIBOM_TEST_COMPONENTS), 1, len(KIBOM_TEST_COMPONENTS)] +LINKS_STATS = [3, '4 (2 SMD/ 2 THT)', '3 (1 SMD/ 2 THT)', 1, 3] VARIANTE_PRJ_INFO = ['kibom-variante', 'default', 'A', '2020-03-12', None] LINK_HEAD = ['References', 'Part', 'Value', 'Quantity Per PCB', 'digikey#', 'digikey_alt#', 'manf#'] LINKS_COMPONENTS = ['J1', 'J2', 'R1'] @@ -774,6 +776,7 @@ def test_int_bom_column_rename_xlsx(test_dir): assert header == KIBOM_RENAME_HEAD ref_column = header.index(REF_COLUMN_NAME_R) check_kibom_test_netlist(rows, ref_column, LINKS_GROUPS, LINKS_EXCLUDE, LINKS_COMPONENTS) + check_head_xlsx(sh_head, LINKS_PRJ_INFO, LINKS_STATS) ctx.clean_up() diff --git a/tests/yaml_samples/int_bom_column_rename_csv.kibot.yaml b/tests/yaml_samples/int_bom_column_rename_csv.kibot.yaml index df2d161e..885de71f 100644 --- a/tests/yaml_samples/int_bom_column_rename_csv.kibot.yaml +++ b/tests/yaml_samples/int_bom_column_rename_csv.kibot.yaml @@ -8,6 +8,7 @@ outputs: type: bom dir: BoM options: + count_smd_tht: true columns: - field: Row name: Renglón diff --git a/tests/yaml_samples/int_bom_column_rename_xlsx.kibot.yaml b/tests/yaml_samples/int_bom_column_rename_xlsx.kibot.yaml index fecbe6fc..a009301f 100644 --- a/tests/yaml_samples/int_bom_column_rename_xlsx.kibot.yaml +++ b/tests/yaml_samples/int_bom_column_rename_xlsx.kibot.yaml @@ -9,6 +9,7 @@ outputs: dir: BoM options: format: XLSX + count_smd_tht: true columns: - field: Row name: Renglón diff --git a/tests/yaml_samples/int_bom_column_rename_xml.kibot.yaml b/tests/yaml_samples/int_bom_column_rename_xml.kibot.yaml index 8232e13f..d4190af2 100644 --- a/tests/yaml_samples/int_bom_column_rename_xml.kibot.yaml +++ b/tests/yaml_samples/int_bom_column_rename_xml.kibot.yaml @@ -9,6 +9,7 @@ outputs: dir: BoM options: format: XML + count_smd_tht: true columns: - field: Row name: Renglón diff --git a/tests/yaml_samples/int_bom_datasheet_link.kibot.yaml b/tests/yaml_samples/int_bom_datasheet_link.kibot.yaml index 97147156..0a4ab0fa 100644 --- a/tests/yaml_samples/int_bom_datasheet_link.kibot.yaml +++ b/tests/yaml_samples/int_bom_datasheet_link.kibot.yaml @@ -11,6 +11,7 @@ outputs: html: datasheet_as_link: 'Part' output: '%f.%x' + count_smd_tht: true columns: - References - Part