abse/smartwatch-flex-top-only
Three-panel flex smartwatch with two parallel R3.9 bends, all components flat-top, low-profile JST connector harnesses, split heartbeat optical windows and screw-retained PCB mounting. Modeled 39 × 50.5 × 14.5mm prototype; 100% routing, zero native DRC and shorts. Hardware qualification pending.
- Version
- 0.2.20
- License
- unset
- Stars
- 0
scripts/audit-plug-in-harnesses.py
from pathlib import Path
import base64,io,json,sys
import numpy as np
import trimesh
root=Path(__file__).resolve().parent.parent
manifest=json.loads((root/'mechanical/harness-manifest.json').read_text())
parts=[]
def load(file,prefix,shift=(0,0,0)):
path=root/f'mechanical/{file}.glb'
if path.exists():s=trimesh.load(path,force='scene')
else:
data=base64.b64decode((root/f'mechanical/{file}.ts').read_text().split('base64,')[1].split('"')[0]);s=trimesh.load(io.BytesIO(data),file_type='glb',force='scene')
for node in s.graph.nodes_geometry:
T,k=s.graph[node];m=s.geometry[k].copy();m.apply_transform(T);m.apply_translation(shift);parts.append((prefix+'/'+node,m))
load(sys.argv[1] if len(sys.argv)>1 else 'ach-placement-upright','pcb')
for file in ['case-body','case-bezel','bezel-bondline','motor-support-shim','optical-windows','optical-light-seal','pcb-cradle','pcb-retainers','pcb-mount-screws','assembly-display','relocated-motor','temperature-probes','motor-inline-connector','button-actuator']:load(file,file)
load('battery-envelope','battery',(3,-.19159126281738,-3.6))
load('ferrite-envelope','ferrite',(0,-8.99159126281738,-6.78))
failures=[];contacts=[];min_distance=1e9
for h in manifest:
manager=trimesh.collision.CollisionManager()
for n,m in parts:
owner='pcb/'+h['pcbRef'] if h['pcbRef'] else None
if owner and (n==owner or n.startswith(owner+'_')):continue
manager.add_object(n,m)
scene=trimesh.load(root/f"mechanical/{h['file']}.glb",force='scene')
for node in scene.graph.nodes_geometry:
T,k=scene.graph[node];m=scene.geometry[k].copy();m.apply_transform(T)
hit,names,data=manager.in_collision_single(m,return_names=True,return_data=True)
distance=manager.min_distance_single(m);min_distance=min(min_distance,float(distance))
for c in data:
record={'harness':h['name'],'mesh':node,'bodies':sorted(c.names),'depthMM':float(c.depth),'pointMM':c.point.tolist()}
# A peripheral's factory-made sealed lead entry is intentional;
# all contacts must be confined to 0.55mm around that entry.
at_factory=np.linalg.norm(np.array(c.point)-np.array(h['factoryPartEntryMM']))<=1.0
expected={'BATTERY_CABLE':'battery/','HAPTIC_CABLE':'motor-inline-connector/','BATTERY_NTC_CABLE':'temperature-probes/BATTERY','COIL_NTC_CABLE':'temperature-probes/COIL','MOTOR_FACTORY_LEADS':'relocated-motor/Neck'}[h['name']]
factory_contact=at_factory and any(n.startswith(expected) for n in c.names)
if h['name']=='MOTOR_FACTORY_LEADS':
at_inline=np.linalg.norm(np.array(c.point)-np.array(h['inlineWireEntryMM']))<=1.0
factory_contact|=at_inline and any(n.startswith('motor-inline-connector/') for n in c.names)
if c.depth>.000005 and not factory_contact:failures.append(record)
contacts.append(record)
report={'status':'PASS' if not failures else 'FAIL','method':'FCL contact detection of actual swept insulated wire and mated housing meshes against every emitted populated PCB/component, enclosure, display, maximum battery/ferrite, motor, mount and temperature-probe mesh. Only each socket\'s intended plug mating and explicitly localized factory lead entries are excluded.',
'harnessesChecked':len(manifest),'bodyMeshes':len(parts),'minimumReportedSurfaceDistanceIncludesFactoryContactsMM':min_distance,'failures':failures,'contactCount':len(contacts)}
(root/'reports/harness-clearance.json').write_text(json.dumps(report,indent=2)+'\n')
# Independently check every wire pair, including wires in one harness.
import itertools,hashlib
wires=[]
for h in manifest:
scene=trimesh.load(root/f"mechanical/{h['file']}.glb",force='scene')
for n in scene.graph.nodes_geometry:
if 'PIN_' not in n and 'FACTORY_PIN' not in n:continue
T,k=scene.graph[n];m=scene.geometry[k].copy();m.apply_transform(T)
assert m.is_watertight and m.is_volume,n
wires.append((h['name']+'/'+n,m))
pair_failures=[]
for (a,x),(b,y) in itertools.combinations(wires,2):
manager=trimesh.collision.CollisionManager();manager.add_object(a,x)
_,_,data=manager.in_collision_single(y,return_names=True,return_data=True)
bad=[c for c in data if c.depth>.000005]
if bad:pair_failures.append({'a':a,'b':b,'contactCount':len(bad),'maxDepthMM':max(float(c.depth) for c in bad)})
pairs={'status':'PASS' if not pair_failures else 'FAIL','wireMeshes':len(wires),'pairCount':len(wires)*(len(wires)-1)//2,'failures':pair_failures,'assetsSha256':{h['file']:hashlib.sha256((root/f"mechanical/{h['file']}.glb").read_bytes()).hexdigest() for h in manifest}}
(root/'reports/harness-wire-pairs.json').write_text(json.dumps(pairs,indent=2)+'\n')
print(json.dumps({k:v for k,v in report.items() if k!='failures'},indent=2));print('Wire pairs',pairs['status'])
assert report['status']=='PASS' and pairs['status']=='PASS'