Add href attribute to connectors, cables, and additional_bom_items

This commit is contained in:
KV 2020-09-14 21:46:06 +02:00
parent dec64abaf5
commit ab077bce67
5 changed files with 43 additions and 16 deletions

View File

@ -2,12 +2,14 @@ templates: # defining templates to be used later on
- &molex_f - &molex_f
type: Molex KK 254 type: Molex KK 254
subtype: female subtype: female
href: "https://www.molex.com/molex/products/family/kk_254_rpc_connector_system"
- &con_i2c - &con_i2c
pinlabels: [GND, +5V, SCL, SDA] pinlabels: [GND, +5V, SCL, SDA]
- &wire_i2c - &wire_i2c
category: bundle category: bundle
gauge: 0.14 mm2 gauge: 0.14 mm2
colors: [BK, RD, YE, GN] colors: [BK, RD, YE, GN]
href: [a, b, c, d]
connectors: connectors:
X1: X1:
@ -67,3 +69,15 @@ connections:
- ferrule_crimp - ferrule_crimp
- W4: [1,2] - W4: [1,2]
- X4: [1,2] - X4: [1,2]
additional_bom_items:
- # define an additional item to add to the bill of materials
description: Label, pinout information
qty: 2
designators:
- X2
- X3
manufacturer: generic company
mpn: Label1
pn: Label-ID-1
href: "https://www.bradyid.com/wire-cable-labels/bmp71-bmp61-m611-tls-2200-nylon-cloth-wire-general-id-labels-cps-2958789"

View File

@ -73,6 +73,7 @@ class AdditionalComponent:
manufacturer: Optional[MultilineHypertext] = None manufacturer: Optional[MultilineHypertext] = None
mpn: Optional[MultilineHypertext] = None mpn: Optional[MultilineHypertext] = None
pn: Optional[Hypertext] = None pn: Optional[Hypertext] = None
href: Optional[PlainText] = None
qty: float = 1 qty: float = 1
unit: Optional[str] = None unit: Optional[str] = None
qty_multiplier: Union[ConnectorMultiplier, CableMultiplier, None] = None qty_multiplier: Union[ConnectorMultiplier, CableMultiplier, None] = None
@ -88,6 +89,7 @@ class Connector:
manufacturer: Optional[MultilineHypertext] = None manufacturer: Optional[MultilineHypertext] = None
mpn: Optional[MultilineHypertext] = None mpn: Optional[MultilineHypertext] = None
pn: Optional[Hypertext] = None pn: Optional[Hypertext] = None
href: Optional[PlainText] = None
style: Optional[str] = None style: Optional[str] = None
category: Optional[str] = None category: Optional[str] = None
type: Optional[MultilineHypertext] = None type: Optional[MultilineHypertext] = None
@ -170,6 +172,7 @@ class Cable:
manufacturer: Union[MultilineHypertext, List[MultilineHypertext], None] = None manufacturer: Union[MultilineHypertext, List[MultilineHypertext], None] = None
mpn: Union[MultilineHypertext, List[MultilineHypertext], None] = None mpn: Union[MultilineHypertext, List[MultilineHypertext], None] = None
pn: Union[Hypertext, List[Hypertext], None] = None pn: Union[Hypertext, List[Hypertext], None] = None
href: Optional[PlainText] = None
category: Optional[str] = None category: Optional[str] = None
type: Optional[MultilineHypertext] = None type: Optional[MultilineHypertext] = None
gauge: Optional[float] = None gauge: Optional[float] = None

View File

@ -14,7 +14,7 @@ from wireviz.wv_colors import get_color_hex
from wireviz.wv_gv_html import nested_html_table, html_colorbar, html_image, \ from wireviz.wv_gv_html import nested_html_table, html_colorbar, html_image, \
html_caption, remove_links, html_line_breaks html_caption, remove_links, html_line_breaks
from wireviz.wv_bom import manufacturer_info_field, component_table_entry, \ from wireviz.wv_bom import manufacturer_info_field, component_table_entry, \
get_additional_component_table, bom_list, generate_bom get_additional_component_table, bom_list, generate_bom, index_if_list
from wireviz.wv_html import generate_html_output from wireviz.wv_html import generate_html_output
from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, flatten2d, \ from wireviz.wv_helper import awg_equiv, mm2_equiv, tuplelist2tsv, flatten2d, \
open_file_read, open_file_write open_file_read, open_file_write
@ -159,7 +159,8 @@ class Harness:
html = [row.replace('<!-- connector table -->', '\n'.join(pinhtml)) for row in html] html = [row.replace('<!-- connector table -->', '\n'.join(pinhtml)) for row in html]
html = '\n'.join(html) html = '\n'.join(html)
dot.node(connector.name, label=f'<\n{html}\n>', shape='none', margin='0', style='filled', fillcolor='white') dot.node(connector.name, label=f'<\n{html}\n>', shape='none', href=connector.href,
margin='0', style='filled', fillcolor='white')
if len(connector.loops) > 0: if len(connector.loops) > 0:
dot.attr('edge', color='#000000:#ffffff:#000000') dot.attr('edge', color='#000000:#ffffff:#000000')
@ -288,10 +289,12 @@ class Harness:
# connections # connections
for connection in cable.connections: for connection in cable.connections:
if isinstance(connection.via_port, int): # check if it's an actual wire and not a shield if isinstance(connection.via_port, int): # check if it's an actual wire and not a shield
dot.attr('edge', color=':'.join(['#000000'] + wv_colors.get_color_hex(cable.colors[connection.via_port - 1], pad=pad) + ['#000000'])) dot.attr('edge', color=':'.join(['#000000'] + wv_colors.get_color_hex(cable.colors[connection.via_port - 1], pad=pad) + ['#000000']),
href=index_if_list(cable.href, connection.via_port - 1))
else: # it's a shield connection else: # it's a shield connection
# shield is shown with specified color and black borders, or as a thin black wire otherwise # shield is shown with specified color and black borders, or as a thin black wire otherwise
dot.attr('edge', color=':'.join(['#000000', shield_color_hex, '#000000']) if isinstance(cable.shield, str) else '#000000') dot.attr('edge', color=':'.join(['#000000', shield_color_hex, '#000000']) if isinstance(cable.shield, str) else '#000000',
href=cable.href if isinstance(cable.href, str) else None)
if connection.from_port is not None: # connect to left if connection.from_port is not None: # connect to left
from_connector = self.connectors[connection.from_name] from_connector = self.connectors[connection.from_name]
from_port = f':p{connection.from_port}r' if from_connector.style != 'simple' else '' from_port = f':p{connection.from_port}r' if from_connector.style != 'simple' else ''
@ -327,6 +330,7 @@ class Harness:
html = '\n'.join(html) html = '\n'.join(html)
dot.node(cable.name, label=f'<\n{html}\n>', shape='box', dot.node(cable.name, label=f'<\n{html}\n>', shape='box',
href=cable.href if isinstance(cable.href, str) else None,
style='filled,dashed' if cable.category == 'bundle' else '', margin='0', fillcolor='white') style='filled,dashed' if cable.category == 'bundle' else '', margin='0', fillcolor='white')
return dot return dot

View File

@ -15,7 +15,7 @@ def get_additional_component_table(harness, component: Union[Connector, Cable])
for extra in component.additional_components: for extra in component.additional_components:
qty = extra.qty * component.get_qty_multiplier(extra.qty_multiplier) qty = extra.qty * component.get_qty_multiplier(extra.qty_multiplier)
if harness.mini_bom_mode: if harness.mini_bom_mode:
id = get_bom_index(harness, extra.description, extra.unit, extra.manufacturer, extra.mpn, extra.pn) id = get_bom_index(harness, extra.description, extra.unit, extra.manufacturer, extra.mpn, extra.pn, extra.href)
rows.append(component_table_entry(f'#{id} ({extra.type.rstrip()})', qty, extra.unit)) rows.append(component_table_entry(f'#{id} ({extra.type.rstrip()})', qty, extra.unit))
else: else:
rows.append(component_table_entry(extra.description, qty, extra.unit, extra.pn, extra.manufacturer, extra.mpn)) rows.append(component_table_entry(extra.description, qty, extra.unit, extra.pn, extra.manufacturer, extra.mpn))
@ -32,7 +32,8 @@ def get_additional_component_bom(component: Union[Connector, Cable]) -> List[dic
'manufacturer': part.manufacturer, 'manufacturer': part.manufacturer,
'mpn': part.mpn, 'mpn': part.mpn,
'pn': part.pn, 'pn': part.pn,
'designators': component.name if component.show_name else None 'designators': component.name if component.show_name else None,
'href': part.href,
}) })
return(bom_entries) return(bom_entries)
@ -49,7 +50,7 @@ def generate_bom(harness):
+ (f', {connector.color}' if connector.color else '')) + (f', {connector.color}' if connector.color else ''))
bom_entries.append({ bom_entries.append({
'item': description, 'qty': 1, 'unit': None, 'designators': connector.name if connector.show_name else None, 'item': description, 'qty': 1, 'unit': None, 'designators': connector.name if connector.show_name else None,
'manufacturer': connector.manufacturer, 'mpn': connector.mpn, 'pn': connector.pn 'manufacturer': connector.manufacturer, 'mpn': connector.mpn, 'pn': connector.pn, 'href': connector.href,
}) })
# add connectors aditional components to bom # add connectors aditional components to bom
@ -68,7 +69,8 @@ def generate_bom(harness):
+ (' shielded' if cable.shield else '')) + (' shielded' if cable.shield else ''))
bom_entries.append({ bom_entries.append({
'item': description, 'qty': cable.length, 'unit': cable.length_unit, 'designators': cable.name if cable.show_name else None, 'item': description, 'qty': cable.length, 'unit': cable.length_unit, 'designators': cable.name if cable.show_name else None,
'manufacturer': cable.manufacturer, 'mpn': cable.mpn, 'pn': cable.pn 'manufacturer': cable.manufacturer, 'mpn': cable.mpn, 'pn': cable.pn,
'href': cable.href if isinstance(cable.href, str) else None,
}) })
else: else:
# add each wire from the bundle to the bom # add each wire from the bundle to the bom
@ -80,7 +82,8 @@ def generate_bom(harness):
bom_entries.append({ bom_entries.append({
'item': description, 'qty': cable.length, 'unit': cable.length_unit, 'designators': cable.name if cable.show_name else None, 'item': description, 'qty': cable.length, 'unit': cable.length_unit, 'designators': cable.name if cable.show_name else None,
'manufacturer': index_if_list(cable.manufacturer, index), 'manufacturer': index_if_list(cable.manufacturer, index),
'mpn': index_if_list(cable.mpn, index), 'pn': index_if_list(cable.pn, index) 'mpn': index_if_list(cable.mpn, index), 'pn': index_if_list(cable.pn, index),
'href': index_if_list(cable.href, index),
}) })
# add cable/bundles aditional components to bom # add cable/bundles aditional components to bom
@ -89,7 +92,7 @@ def generate_bom(harness):
for item in harness.additional_bom_items: for item in harness.additional_bom_items:
bom_entries.append({ bom_entries.append({
'item': item.get('description', ''), 'qty': item.get('qty', 1), 'unit': item.get('unit'), 'designators': item.get('designators'), 'item': item.get('description', ''), 'qty': item.get('qty', 1), 'unit': item.get('unit'), 'designators': item.get('designators'),
'manufacturer': item.get('manufacturer'), 'mpn': item.get('mpn'), 'pn': item.get('pn') 'manufacturer': item.get('manufacturer'), 'mpn': item.get('mpn'), 'pn': item.get('pn'), 'href': item.get('href'),
}) })
# remove line breaks if present and cleanup any resulting whitespace issues # remove line breaks if present and cleanup any resulting whitespace issues
@ -97,7 +100,7 @@ def generate_bom(harness):
# deduplicate bom # deduplicate bom
bom = [] bom = []
bom_types_group = lambda bt: (bt['item'], bt['unit'], bt['manufacturer'], bt['mpn'], bt['pn']) bom_types_group = lambda bt: (bt['item'], bt['unit'], bt['manufacturer'], bt['mpn'], bt['pn'], bt['href'])
for group in Counter([bom_types_group(v) for v in bom_entries]): for group in Counter([bom_types_group(v) for v in bom_entries]):
group_entries = [v for v in bom_entries if bom_types_group(v) == group] group_entries = [v for v in bom_entries if bom_types_group(v) == group]
designators = [] designators = []
@ -118,24 +121,25 @@ def generate_bom(harness):
bom = [{**entry, 'id': index} for index, entry in enumerate(bom, 1)] bom = [{**entry, 'id': index} for index, entry in enumerate(bom, 1)]
return bom return bom
def get_bom_index(harness, item, unit, manufacturer, mpn, pn): def get_bom_index(harness, item, unit, manufacturer, mpn, pn, href):
# Remove linebreaks and clean whitespace of values in search # Remove linebreaks and clean whitespace of values in search
target = tuple(clean_whitespace(v) for v in (item, unit, manufacturer, mpn, pn)) target = tuple(clean_whitespace(v) for v in (item, unit, manufacturer, mpn, pn, href))
for entry in harness.bom(): for entry in harness.bom():
if (entry['item'], entry['unit'], entry['manufacturer'], entry['mpn'], entry['pn']) == target: if (entry['item'], entry['unit'], entry['manufacturer'], entry['mpn'], entry['pn'], entry['href']) == target:
return entry['id'] return entry['id']
return None return None
def bom_list(bom): def bom_list(bom):
keys = ['id', 'item', 'qty', 'unit', 'designators'] # these BOM columns will always be included keys = ['id', 'item', 'qty', 'unit', 'designators'] # these BOM columns will always be included
for fieldname in ['pn', 'manufacturer', 'mpn']: # these optional BOM columns will only be included if at least one BOM item actually uses them for fieldname in ['pn', 'manufacturer', 'mpn', 'href']: # these optional BOM columns will only be included if at least one BOM item actually uses them
if any(entry.get(fieldname) for entry in bom): if any(entry.get(fieldname) for entry in bom):
keys.append(fieldname) keys.append(fieldname)
bom_list = [] bom_list = []
# list of staic bom header names, headers not specified here are generated by capitilising the internal name # list of staic bom header names, headers not specified here are generated by capitilising the internal name
bom_headings = { bom_headings = {
"pn": "P/N", "pn": "P/N",
"mpn": "MPN" "mpn": "MPN",
"href": "URL",
} }
bom_list.append([(bom_headings[k] if k in bom_headings else k.capitalize()) for k in keys]) # create header row with keys bom_list.append([(bom_headings[k] if k in bom_headings else k.capitalize()) for k in keys]) # create header row with keys
for item in bom: for item in bom:

View File

@ -36,6 +36,8 @@ def generate_html_output(filename: (str, Path), bom_list):
file.write('<tr>') file.write('<tr>')
for i, item in enumerate(row): for i, item in enumerate(row):
item_str = item.replace('\u00b2', '&sup2;') item_str = item.replace('\u00b2', '&sup2;')
if listy[0][i] == 'URL':
item_str = f'<a href="{item}">{item_str}</a>'
align = 'text-align:right; ' if listy[0][i] == 'Qty' else '' align = 'text-align:right; ' if listy[0][i] == 'Qty' else ''
file.write(f'<td style="{align}border:1px solid #000000; padding: 4px">{item_str}</td>') file.write(f'<td style="{align}border:1px solid #000000; padding: 4px">{item_str}</td>')
file.write('</tr>') file.write('</tr>')