AnasSarkiz/magnetic-shutter-remote-r8
A USB‑C rechargeable battery-powered ESP32‑C3 wireless controller with Li‑ion charging, protected 3.3‑V buck‑boost regulation, thermal/safety monitoring, status LEDs, buttons, programming UART, crystal clock, and 2.4‑GHz antenna matching network.
- Version
- 0.4.0-prototype
- License
- unset
- Stars
- 0
scripts/audit-r8-jst3.py
"""Check original supplier conversion and JST SH catalogue nominal tolerances."""
import json
import re
import hashlib
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
EVIDENCE = ROOT / 'evidence/R8-standard-programmer-2026-10-05/qualification'
def audit():
raw = json.loads((EVIDENCE/'C160389-supplier.json').read_text())['easyeda_component_details']['easyeda_json']
assert raw['lcsc']['number'] == 'C160389'
text = (ROOT/'imports/BM03B_SRSS_TB_LF__SN_/BM03B_SRSS_TB_LF__SN_.tsx').read_text()
assert 'manufacturerPartNumber="BM03B-SRSS-TB(LF)(SN)"' in text
shapes = [s.split('~') for s in raw['packageDetail']['dataStr']['shape'] if s.startswith('PAD~')]
assert len(shapes) == 5 and all(s[1] == 'RECT' for s in shapes)
x = [float(s[2])+sign*float(s[4])/2 for s in shapes for sign in [-1,1]]
y = [float(s[3])+sign*float(s[5])/2 for s in shapes for sign in [-1,1]]
ox,oy = (max(x)+min(x))/2,(max(y)+min(y))/2
pads, differences = {}, []
for s in shapes:
pin=s[8]
match=re.search(r'<smtpad portHints=\{\["pin'+pin+r'"\]\} (.*?) />',text)
assert match, pin
actual=[float(re.search(key+r'="([-\d.]+)mm"',match[1])[1]) for key in ['pcbX','pcbY','width','height']]
expected=[(float(s[2])-ox)*.254,(oy-float(s[3]))*.254,float(s[4])*.254,float(s[5])*.254]
differences.extend(abs(a-b) for a,b in zip(actual,expected))
pads[pin]=dict(zip(['x_mm','y_mm','width_mm','height_mm'],actual))
assert set(pads) == {'1','2','3','4','5'} and max(differences) < 1e-7
for pin,p in pads.items():
signal=int(pin)<=3
assert abs(p['width_mm']-(.6 if signal else 1.2)) <= (.05 if signal else .1)
assert abs(p['height_mm']-(1.55 if signal else 1.8)) <= .1
assert abs(p['x_mm']-({'1':1,'2':0,'3':-1,'4':2.3,'5':-2.3}[pin])) <= .05
pitch=abs(pads['1']['x_mm']-pads['2']['x_mm'])
span=max(p['y_mm']+p['height_mm']/2 for p in pads.values())-min(p['y_mm']-p['height_mm']/2 for p in pads.values())
assert abs(pitch-1)<=.05 and abs(span-4.2)<=.1
assert abs(pads['1']['y_mm']-pads['4']['y_mm']- (4.2-.775-.9))<=.05
for ext in ['obj','step']:
data=(ROOT/f'imports/BM03B_SRSS_TB_LF__SN_/BM03B_SRSS_TB_LF__SN_.{ext}').read_text()
assert ('\nv ' in data and '\nf ' in data) if ext=='obj' else ('ISO-10303-21;' in data and 'END-ISO-10303-21;' in data)
result={'status':'PASS','part':'C160389','mpn':'BM03B-SRSS-TB(LF)(SN)','supplier_uuid':raw['uuid'],
'maximum_conversion_difference_mm':max(differences),'pitch_mm':pitch,'copper_span_y_mm':span,'pads':pads,
'manufacturer_source':'references/JST-SH.pdf, page1 top-entry lands and page3 header table',
'manufacturer_sha256':hashlib.sha256((ROOT/'references/JST-SH.pdf').read_bytes()).hexdigest(),
'mating_direction':'+Z / top entry','contacts':{'1':'UART_RX','2':'GND','3':'UART_TX'},
'anchors':'4/5 are insulated mechanical supports; explicitly tied to PCB GND, not UART contacts',
'limitations':['Nominal manufacturer land guidance; physical mating and assembled enclosure clearance remain untested.']}
(EVIDENCE/'land-audit.json').write_text(json.dumps(result,indent=2)+'\n')
print('Exact supplier conversion and JST nominal land tolerances PASS:',max(differences),'mm')
return result
if __name__=='__main__':
audit()