component
JST SM04B-GHS-TB(LF)(SN) GH 4-circuit side entry SMT header
Public Made by Adomby adom
JST GH 1.25 mm pitch, 4 circuits, side entry (right angle) SMT shrouded header with two solder tabs; mates with GHR-04V-S and SSHL-002T-P0.2.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
#!/usr/bin/env python3
"""Write provenance/sources.json, provenance/3d-model.json, lod/manifest.json and models.json for
adom/sm04b-ghs-tb-lf-sn from the files in the page tree (run from the page root).
Hashes are sha256 of the bytes as published; git_blob is the git blob id (what the wiki serves)."""
import hashlib, json, os, subprocess, sys
D = '2026-10-21'
def sha(p): return hashlib.sha256(open(p, 'rb').read()).hexdigest()
def blob(p):
b = open(p, 'rb').read(); return hashlib.sha1(b'blob %d\0' % len(b) + b).hexdigest()
def size(p): return os.path.getsize(p)
stats = {s['file']: s for s in json.loads(subprocess.check_output([sys.executable, 'provenance/tools/glbtool.py', 'stats',
'sm04b-ghs-tb-lf-sn.glb', 'sm04b-ghs-tb-lf-sn-hero.glb'] + [f'lod/sm04b-ghs-tb-lf-sn-{l}.glb' for l in ('high', 'medium', 'low', 'super-low')]))}
STEP = 'sm04b-ghs-tb-lf-sn.step'
KICAD_STEP_URL = 'https://gitlab.com/kicad/libraries/kicad-packages3D/-/raw/master/Connector_JST.3dshapes/JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal.step'
KICAD_FP_URL = 'https://gitlab.com/kicad/libraries/kicad-footprints/-/raw/master/Connector_JST.pretty/JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal.kicad_mod'
DS = 'docs/sm04b-ghs-tb-lf-sn-datasheet.pdf'
sources = {
'schema': 'adom/sources@1', 'mpn': 'SM04B-GHS-TB(LF)(SN)', 'date': D,
'datasheet': {'title': 'JST GH CONNECTOR, 1.25 mm pitch disconnectable crimp style connectors (catalog eGH)', 'file': DS,
'sha256': sha(DS), 'bytes': size(DS), 'pages': 2, 'pdf_info': 'Title eGH.doc, created 2016-11-18 (Acrobat Distiller 4.05); no revision identifier printed',
'official_url': 'https://www.jst-mfg.com/product/pdf/eng/eGH.pdf',
'retrieved_from': 'https://jlcpcb.com/api/file/downloadByFileSystemAccessId/8588905132734365696 (the datasheet JLCPCB links for C189895)',
'retrieval_note': 'On 2026-10-21 www.jst-mfg.com refused TCP connections from the build host and jst.com answered 403, so the file was taken from the JLCPCB part record. It is JST eGH.pdf (JST title, layout and page numbering). Compare with the official URL before relying on a later revision.',
'cited_pages': {'p.1': 'Specifications; PC board layout, side entry type; Contact SSHL-002T-P0.2', 'p.2': 'Housing GHR-xxV-S; Shrouded header side entry type (Circuit No.1, A and B dimensions, 4.05 / 0.8 / 4.25); Material and Finish; RoHS (LF)(SN) label'},
'figures': sorted('docs/figures/' + f for f in os.listdir('docs/figures'))},
'footprint': {'file': 'sm04b-ghs-tb-lf-sn.kicad_mod', 'sha256': sha('sm04b-ghs-tb-lf-sn.kicad_mod'),
'upstream': 'KiCad Connector_JST:JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal (kicad-footprint-generator, file version 20260206)', 'upstream_url': KICAD_FP_URL,
'upstream_sha256': '%s' % sha('provenance/upstream/JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal.kicad_mod'),
'changes': ['footprint name -> sm04b-ghs-tb-lf-sn (matches the file name)', 'Value -> SM04B-GHS-TB(LF)(SN)', '3D model path -> ${KIPRJMOD}/sm04b-ghs-tb-lf-sn.step'],
'pads_changed': False, 'check': 'provenance/footprint-vs-jst.json', 'license': 'CC-BY-SA-4.0 with the KiCad library exception (LICENSE-KICAD.md)'},
'symbol': {'file': 'sm04b-ghs-tb-lf-sn.kicad_sym', 'sha256': sha('sm04b-ghs-tb-lf-sn.kicad_sym'), 'tool': 'adom-symbol 1.2.6 create (provenance/symbol-create.json), --no-chip-outline',
'post_edit': 'provenance/tools/symbol_post.py: pins moved onto the 2.54 mm grid (adom-symbol 1.2.6 put them at y -2.00, -4.54, ...), body narrowed, Footprint property set, generator sentence trimmed from Description',
'license': 'CC-BY-4.0 (Adom-authored)'},
'lbr': {'file': 'sm04b-ghs-tb-lf-sn.lbr', 'sha256': sha('sm04b-ghs-tb-lf-sn.lbr'), 'tool': 'adom-lbr 2.47.5 generate --symbol-layout keep --part-metadata page.json --package-name SM04B-GHS-TB',
'post_edit': 'MP pin direction io -> nc (adom-lbr 2.47.5 writes a KiCad no_connect pin as io); lint passes after the edit'},
'altium': {'files': {f: sha('altium/' + f) for f in sorted(os.listdir('altium'))}, 'tool': 'adom-lbr 2.47.5 import-kicad, then assemble-altium --no-dedupe with the page STEP beside the hub JSON (1 model embedded)',
'round_trip': 'adom-lbr import-altium of the SchLib + PcbLib gives the same 5 pins and 6 pads; MP reads back as Passive (Altium has no no-connect pin type)'},
'distributors': {'tool': 'adom-parts-search search SM04B-GHS-TB(LF)(SN), 2026-10-21', 'mouser': '306-SM04BGHSTBLFSN (exact MPN, 762 in stock)',
'digikey': '455-1566-2-ND (listed as SM04B-GHS-TB, JST Sales America; 0 in stock; status Active)', 'lcsc': 'C189895 (exact MPN, 5,852 in stock)'},
}
json.dump(sources, open('provenance/sources.json', 'w'), indent=1)
def dim(item, jst, model, ok, note=''):
return {'item': item, 'jst': jst, 'model': model, 'match': ok, **({'note': note} if note else {})}
model3d = {
'schema': 'adom/3d-model-provenance@1', 'mpn': 'SM04B-GHS-TB(LF)(SN)', 'date': D,
'classification': "KiCad library model (community CAD, nominal geometry), unchanged; checked against JST's drawing. Not JST CAD.",
'manufacturer_step': {'status': 'not obtained', 'tried': [
{'url': 'https://www.jst-mfg.com/product/pdf/eng/eGH.pdf and the jst-mfg.com product pages', 'result': 'TCP connection refused from the build host, 2026-10-21'},
{'url': 'https://www.jst.com/products/crimp-style-connectors-wire-to-board-type/gh-connector/', 'result': 'HTTP 403 (bot wall), 2026-10-21'}],
'note': "JST's CAD downloads sit on jst-mfg.com behind its product pages; a browser session would be needed. When JST's STEP is added, keep its bytes in vendor/ and compare it with this model."},
'source': {'file': STEP, 'sha256': sha(STEP), 'bytes': size(STEP), 'url': KICAD_STEP_URL,
'header': 'JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal.step, Copyright (C) 2018 Frank Severinsen, CC-BY-SA 4.0 with the KiCad library exception',
'bytes_changed': False, 'units': 'mm', 'up_axis': 'Z', 'seating_plane': 'z = 0 (housing underside at z = -0.005)', 'origin': 'KiCad footprint origin; binds with zero offset and rotation'},
'frame': 'Z up, seated on z = 0, centred on the KiCad footprint origin, 3D +Y = footprint -Y (KiCad convention): contact tails toward +Y, mating face toward -Y',
'measured_with': 'service-step2glb features (bounding box) and per-primitive bounds of the step2glb GLB (provenance/tools/glb_parts.mjs keeps the two step2glb materials: mat_0 housing, mat_1 contacts and tabs)',
'dimensions_mm': [
dim('B overall width incl. solder tabs (4 circuits)', '8.25 (p.2 table)', '8.250 (x -4.125 .. 4.125)', True),
dim('A outer contact span', '3.75 (p.2 table)', '3.750 (contact centres x -1.875 .. 1.875)', True),
dim('contact pitch', '1.25', '1.250', True),
dim('contact tail width', '0.2 (p.2)', '0.200', True),
dim('housing depth, mating face to rear', '4.05 (p.2 side view)', '4.050 (y -2.470 .. 1.580)', True),
dim('contact tail beyond housing rear', '0.8 (p.2 side view)', '0.895 (tail tip y 2.475)', False, 'KiCad tails are 0.095 mm longer than JST draws. The tip still lands 0.225 mm inside the 1.7 mm signal pad (pad rear edge at 3D y 2.7), so it has no effect on the land pattern or the board outline.'),
dim('height above board', '4.25 (p.2 front view)', '4.250 (z -0.005 .. 4.245)', True),
dim('solder tab inner face to circuit 4 centre', '1.75 (p.2 front view)', '1.750 (tab x 3.625 .. 3.825)', True),
dim('solder tab centre (= footprint MP pad centre)', '3.725 (p.1 layout: 1.35 + 1.0 / 2 from the outer contact)', '3.725', True),
dim('housing front vs footprint header outline', '0.25 behind the tab pad front edge (p.1 layout), footprint y 2.45', 'housing front at footprint y 2.47', True, 'within 0.02 mm'),
dim('mated height with GHR housing', '4.35 (p.1 assembly layout)', 'not checkable (no housing in this model)', None)],
'pin1': {'footprint': 'pad 1 at x = -1.875 (the -X end)', 'model': 'contact at x = -1.875 is circuit 1; the four contacts sit on pads 1 to 4 with zero offset',
'datasheet': 'p.2 side entry view (looking into the mating face, board below) labels Circuit No.1 at the left; with the mating face toward 3D -Y the viewer facing it has -X on the left',
'render': 'docs/models/sm04b-ghs-tb-lf-sn-glb-front.png (view along +Y onto the mating face: circuit 1 at the left, as JST draws it)',
'note': 'The KiCad model has no pin-1 mark (nor does the real header; JST marks circuit 1 only in the drawing). Its contact pattern is symmetric, so orientation rests on the footprint binding and the mating face direction, both checked.'},
'simplifications': ['Housing latch window, polarising ribs and cavity detail are simplified boxes, not JST geometry.', 'Contacts are rectangular sections without bend radii.', 'No marking: the real header carries none.'],
'glb': {'converter': 'step2glb convert --compress none (service-step2glb)', 'post': 'provenance/tools/glb_parts.mjs (glTF Transform 4.1.1): split into named nodes housing and contacts, materials housing PA9T ivory metallic 0 roughness 0.6, contacts tin metallic 1 roughness 0.35, dedup + join per part + prune',
'file': 'sm04b-ghs-tb-lf-sn.glb', 'sha256': sha('sm04b-ghs-tb-lf-sn.glb')},
'hero': {'file': 'sm04b-ghs-tb-lf-sn-hero.glb', 'sha256': sha('sm04b-ghs-tb-lf-sn-hero.glb'), 'tool': 'adom/component-hero hero_glb.py (adom-hero 1.4)', 'result': 'pads 6, silk items 6, pin-1 dot added (AI) beside pad 1, labels 5, align OK (offset 0.0 mm)', 'overlay': 'sm04b-ghs-tb-lf-sn-hero.overlay.json'},
'virtual_mpn_mark': 'Not applied. The real header has no marking and its top is a 3 mm deep ivory moulding; an etched MPN would read as a real marking. Recorded as an open item.',
}
json.dump(model3d, open('provenance/3d-model.json', 'w'), indent=1)
levels = []
deriv = {'high': 'board-use GLB: housing and contacts batched per part, uncompressed (lossless; same file as sm04b-ghs-tb-lf-sn.glb)',
'medium': 'high, KHR_mesh_quantization', 'low': 'weld + meshopt simplify ratio 0.5 error 0.002, quantized',
'super-low': 'weld + meshopt simplify ratio 0.25 error 0.01, quantized'}
for l in ('high', 'medium', 'low', 'super-low'):
p = f'lod/sm04b-ghs-tb-lf-sn-{l}.glb'; s = stats[os.path.basename(p)]; png = p[:-4] + '.png'
levels.append({'level': l, 'path': p, 'sha256': s['sha256'], 'sizeBytes': s['bytes'], 'decodedBufferBytes': s['decodedBytes'], 'triangles': s['triangles'],
'primitives': s['primitives'], 'boundsMm': s['boundsMm'], 'markingIncluded': False, 'helperNodes': s['helperNodes'], 'extensions': s['extensions'],
'derivation': deriv[l], 'review': 'candidate: inspected as cached images; not qualified in a streaming LOD viewer',
'preview': {'path': png, 'sha256': sha(png), 'sizeBytes': size(png), 'width': 400, 'height': 400, 'view': 'iso (front-left, from above), same camera on every level', 'sourceLevelSha256': s['sha256']}})
lod = {'schema': 'adom/component-lod@1', 'mpn': 'SM04B-GHS-TB(LF)(SN)', 'units': 'metres (glTF)', 'upAxis': 'Z (Adom/KiCad frame; seated on z = 0, centred on the footprint origin)',
'status': 'candidate', 'source': {'path': STEP, 'sha256': sha(STEP)},
'generator': 'step2glb convert --compress none -> provenance/tools/glb_parts.mjs (glTF Transform 4.1.1, meshoptimizer 0.22.0); previews by provenance/tools/render.py',
'note': 'The KiCad model is already low-poly (756 triangles, all planar faces), so simplification removes few triangles (744 low, 722 super-low); the lower levels mainly save bytes through quantization. No level carries footprint copper, pad labels or silkscreen; none carries a marking (the part has none).',
'levels': levels}
json.dump(lod, open('lod/manifest.json', 'w'), indent=1)
def rec(path, fmt, title, slot, variant, use, unique, role, derived_from, source, thumb, thumb_bottom=None):
r = {'path': path, 'format': fmt, 'title': title, 'status': 'current', 'slot': slot, 'variant': variant, 'use': use, 'unique': unique,
'marking': None, 'sha256': sha(path), 'git_blob': blob(path), 'bytes': size(path), 'role': role, 'colours': True,
'derived_from': derived_from, 'source': source, 'thumb': thumb}
if thumb_bottom: r['thumb_bottom'] = thumb_bottom
return r
models = {'schema': 'adom/models@1', 'part': 'SM04B-GHS-TB(LF)(SN)', 'models': [
rec(STEP, 'step', 'SM04B-GHS-TB(LF)(SN), KiCad library model (library model for board CAD)', 'model_3d_step', 'plain', ['board-cad'],
"KiCad's JST_GH_SM04B-GHS-TB model, bytes unchanged; checked against JST's drawing (provenance/3d-model.json)", 'community-library', None,
KICAD_STEP_URL, 'docs/models/sm04b-ghs-tb-lf-sn-glb-top.png', 'docs/models/sm04b-ghs-tb-lf-sn-glb-bottom.png'),
rec('sm04b-ghs-tb-lf-sn.glb', 'glb', 'SM04B-GHS-TB(LF)(SN), board-use GLB', 'model_3d_plain', 'plain', ['render', 'board-insertion'],
'Web and board-viewer copy of the STEP: named housing and contacts nodes with ivory and tin materials, no reference artwork', 'derived', STEP,
'step2glb + provenance/tools/glb_parts.mjs', 'docs/models/sm04b-ghs-tb-lf-sn-glb-iso.png'),
rec('sm04b-ghs-tb-lf-sn-hero.glb', 'glb', 'SM04B-GHS-TB(LF)(SN), annotated hero', 'model_3d', 'hero', ['wiki-hero'],
'The board-use model plus nonphysical reference art: teal dashed pad outlines, silkscreen with a pin-1 dot, pad numbers (adom-hero 1.4); never for a board',
'derived', 'sm04b-ghs-tb-lf-sn.glb', 'adom/component-hero hero_glb.py', 'docs/proof/sm04b-ghs-tb-lf-sn-hero-preview.png')] + [
rec(f'lod/sm04b-ghs-tb-lf-sn-{l}.glb', 'glb', f'SM04B-GHS-TB(LF)(SN), {l} detail level', None, 'lod', ['board-insertion'],
{'high': 'Same bytes as the board-use GLB', 'medium': 'Quantized', 'low': 'Simplified 0.5 and quantized', 'super-low': 'Simplified 0.25 and quantized'}[l],
'derived', 'sm04b-ghs-tb-lf-sn.glb', 'lod/manifest.json', f'lod/sm04b-ghs-tb-lf-sn-{l}.png') for l in ('high', 'medium', 'low', 'super-low')]}
json.dump(models, open('models.json', 'w'), indent=1)
print('OK sources, 3d-model, lod manifest, models.json')