AnasSarkiz/muse-voice-remote
Muse Voice Remote — bare ESP32-S3R8, 155 TOP JLCPCB parts with real supplier CAD, native 3D assembly and GLB exports. Revised 17 mm case allocation; 0.30 mm via drill /0.45 mm pad. Checked prototype PCB; mechanical, RF and MUSE qualification pending.
- Version
- 1.3.2
- License
- unset
- Stars
- 0
scripts/replace-imported-footprints.py
#!/usr/bin/env python3
"""Transplant selected supplier footprints from a current unrouted seed.
This preserves other footprints and existing copper. It does not approve that
copper: refill zones, repair affected connections and run independent DRC.
"""
import argparse
import json
from pathlib import Path
import pcbnew
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--base", required=True)
parser.add_argument("--seed", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("references", nargs="+")
args = parser.parse_args()
root = Path(__file__).resolve().parents[1]
base = pcbnew.LoadBoard(args.base)
seed = pcbnew.LoadBoard(args.seed)
old = {f.GetReference(): f for f in base.GetFootprints()}
fresh = {f.GetReference(): f for f in seed.GetFootprints()}
catalog = {p["reference"]: p for p in json.loads((root/"docs/component-catalog.json").read_text())}
nets = {n.GetNetname(): n for n in base.GetNetInfo().NetsByNetcode().values()}
for ref in args.references:
source = fresh[ref]
entry = catalog[ref]
lcsc = entry["lcsc"]
if source.GetValue() != entry["mpn"]:
raise RuntimeError(f"Stale seed footprint: {ref}")
footprint = pcbnew.FootprintLoad(str(root/"vendor/jlcpcb/library"), lcsc)
footprint.SetReference(ref)
footprint.SetValue(source.GetValue())
footprint.SetPosition(source.GetPosition())
footprint.SetOrientationDegrees(source.GetOrientationDegrees())
footprint.Reference().SetVisible(False)
footprint.Value().SetVisible(False)
assigned = {p.GetNumber(): p.GetNetname() for p in source.Pads()}
for pad in footprint.Pads():
name = assigned.get(pad.GetNumber())
if name:
pad.SetNet(nets[name])
for graphic in footprint.GraphicalItems():
if graphic.GetLayer()==pcbnew.F_SilkS:
graphic.SetLayer(pcbnew.F_Fab)
base.Remove(old[ref])
base.Add(footprint)
print(f"Replaced {ref} with supplier {lcsc} {entry['mpn']}")
for footprint in base.GetFootprints():
if footprint.GetReference() in catalog:
footprint.SetAttributes(pcbnew.FP_SMD)
pcbnew.SaveBoard(args.output, base)