# -*- coding: utf-8 -*- u"""⛔⛔ **这个脚本已经过期,不要再 `--push`**(2026-09-06 起)。 它是「整页重画导线 / 旗 / 文字」的写法,几何底稿是 `p1-base.json` —— 那份快照停在 2026-09-04,**不知道后来的两轮改动**: * `p1_r9f1.py`:R9 拆成 R9A~R9E(5 × 2Ω 2512 串联),F1 换成 12 A 那颗; * `p1_text_fix.py`:说明文字去重 + Rs6/U13 那一组挪到 R9 链下方。 再推一次的后果是**静默回退**:BASE 里那条 `(780,300)-(780,270)` 和 (780,270) 的 GND 旗会被重新画出来,而 R9A~R9E 之间那 6 段新导线一条都不在 BASE 里 ⇒ 五颗电阻串在半空中。`verify_sch.py` 会报「单引脚网络」,但要跑了才知道, 而 PCB 那边已经按新网表扇完出、铺完铜了。 真要再改这一页,就照 `p1_r9f1.py` 的写法做**增量**(先 create 后 delete、 旗删掉重建、坐标全 5 的倍数),别再整页重画。 ──────────────────────────────────────────────────────────── 原说明(留作记录):P1-INPUT 加输入侧 INA226(U13 + Rs6 + C11)。 几何底稿是 `p1-base.json`(加 U13 之前的整页回读快照)。 导线 / 旗 / 文字整页重画,**端口不动**——当时以为 P1 那 14 个端口的 dir(IN/OUT/BI) API 读不回来,重建会把标签方向全弄错,所以只增量加 3 个新端口。 ⚠️ **2026-09-06 更正:dir 读得回来** —— `getState_Component().name` 就是 `Netport-BI` / `Netport-IN` / `Netport-OUT`(skill §8b 末尾)。这一条限制可以解除了; `.claude/pinmap.py` 就是靠它整批删掉重建端口的。 拓扑:Q1 漏极 → 体电容 C2~C6 / D1 → **Rs6(5mΩ)** → +12V(送五路 + 辅助 Buck + 泄放) 体电容在 Rs6 **上游**,Rs6 量到的是负载电流;开关纹波由各路自己的输入 MLCC 就近提供。 PCB 上 Rs6 要放在体电容与五路分叉点之间,Kelvin 四线焊盘。 排版上被两件事挤着,坐标是照着它们定的: · U13 的型号文字 `INA226AIDGSR` 画在符号右边约 30~90 个单位处,宽 60, 所有旗都得躲开 x 933~993 / y 632~645 这一块; · FB3V3 端口的标签一直伸到 x≈870(y 458~472),左边那几条竖线只能走 x≥845。 用法: python .claude/p1_add.py [--push] """ import io, json, os, sys HERE = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, HERE) from eda import run PAGE = '9a6096762e036e23' BASE = json.load(io.open(os.path.join(HERE, 'p1-base.json'), encoding='utf-8')) DROP_WIRE = [((780, 770), (900, 770))] # 12V 母线右段,被 Rs6 一分为二 # U29(TL431) 的 REF / 阴极原来和 BLD_REF / BLD_A 两个端口**引脚坐标完全重合**, # 靠零长度导线"连着"——和 P2 上 K1_VUP 是同一个毛病(见 §16.5)。 # 端口往左挪 40,补一段真导线。删掉旧的那两个端口,坐标见 DROP_PORT_XY。 DROP_PORT_XY = [(240, 200), (240, 190)] DROP_FLAG = ['+12V', 900, 770, 0] # +12V 旗挪到 Rs6 下游 ADD_WIRE = [ ((780, 770), (880, 770)), # 母线 -> Rs6.1(上游) ((920, 770), (960, 770)), # Rs6.2(下游)-> +12V 旗 ((880, 670), (880, 770)), # VIN+ -> Rs6 上游焊盘 ((890, 670), (890, 720)), ((890, 720), (920, 720)), ((920, 720), (920, 770)), # VIN- ((900, 670), (900, 720)), # VBUS 搭到 VIN- 上(测母线电压) ((910, 670), (910, 700)), ((910, 700), (1120, 700)), ((1120, 700), (1120, 675)), # GND ((920, 670), (920, 680)), ((920, 680), (1080, 680)), ((1080, 680), (1080, 660)), # VS+ -> C11.1 ((1030, 680), (1030, 665)), # +3V3 旗(Power rot180,挂在导线下面) ((1080, 620), (1080, 605)), # C11.2 -> GND ((880, 570), (880, 545)), ((880, 545), (855, 545)), ((855, 545), (855, 500)), # A1 -> GND ((890, 570), (890, 440)), ((890, 440), (850, 440)), ((850, 440), (850, 320)), ((850, 320), (920, 320)), # A0 -> SCL ((900, 570), (900, 420)), # Alert ((910, 570), (910, 380)), # SDA ((920, 570), (920, 320)), # SCL(A0 搭在它下端) ((200, 200), (240, 200)), # BLD_REF -> U29.REF(原来是零长度导线) ((200, 190), (240, 190)), # BLD_A -> U29 阴极(同上) ] ADD_FLAG = [ ('+12V', 960, 770, 0), ('GND', 1120, 675, 0), ('GND', 1080, 605, 0), ('+3V3', 1030, 665, 180), # rot180 = 引脚在上、符号挂在下面 ('GND', 855, 500, 0), ] ADD_PORT = [ ('INA_ALERT', 900, 420, 0, 'OUT'), ('SDA', 910, 380, 0, 'BI'), ('SCL', 920, 340, 0, 'BI'), # BLD_REF / BLD_A 全部重建(清空那一步是按**网络名**删端口的,会把同名的都删掉)。 # dir 按截图上标签的朝向反推:五个都是标签背着导线走,等价于 BI。 ('BLD_REF', 200, 200, 180, 'BI'), # 原来在 (240,200),和 U29.REF 引脚重合 ('BLD_A', 200, 190, 180, 'BI'), # 原来在 (240,190),和 U29 阴极重合 ('BLD_REF', 80, 235, 0, 'BI'), ('BLD_A', 385, 225, 0, 'BI'), ('BLD_A', 545, 280, 180, 'BI'), ] ADD_TEXT = [ ('【D】输入侧电流 / 电压监测', 850, 800, 12), ('Rs6 5mΩ: 满板约 8A -> 40mV(满量程 81.92mV)', 850, 300, 9), ('U13: A1=GND / A0=SCL -> 0x43(地址表见 §8.2)', 850, 287, 9), ('体电容在 Rs6 上游;PCB 上 Rs6 放在体电容与', 850, 274, 9), ('五路分叉点之间,Kelvin 四线焊盘', 850, 261, 9), ] # 元件位置(place 见 __main__;坐标一改这里也要改) PARTS = [ ('U13', 'c19abc37bc174e89b3cbd0176ec08490', 900, 620, 90), ('Rs6', '845ad0fe0ddd489189487bf9c35bcea3', 900, 770, 0), ('C11', '87bb635d0b2f489a9f60e7cd225beb3c', 1080, 640, 270), ] OPEN = "await eda.dmt_EditorControl.openDocument('%s');" % PAGE def call(body, timeout=180): r = run(OPEN + body, timeout=timeout) if not r.get('success'): print('失败:', json.dumps(r, ensure_ascii=False)[:400]); sys.exit(1) return r['result'] def build(): drop_w = {tuple(sorted(w)) for w in DROP_WIRE} wires = [tuple(map(tuple, w)) for w in BASE['wires'] if tuple(sorted(map(tuple, w))) not in drop_w] assert len(wires) == len(BASE['wires']) - 1, '要删的母线段没找到' wires += ADD_WIRE flags = [tuple(f) for f in BASE['flags'] if list(f) != DROP_FLAG] assert len(flags) == len(BASE['flags']) - 1, '要删的 +12V 旗没找到' flags += ADD_FLAG texts = [tuple(t) for t in BASE['texts']] + ADD_TEXT return wires, flags, texts def chunk(xs, k): for i in range(0, len(xs), k): yield xs[i:i + k] if __name__ == '__main__': if '--push' in sys.argv and '--i-know-it-is-stale' not in sys.argv: sys.exit(u'⛔ p1_add.py 已过期,重推会把 R9A~R9E 的连线静默回退。' u'理由见文件头;确实要跑就加 --i-know-it-is-stale。') wires, flags, texts = build() print('导线 %d 旗 %d 文字 %d 新增端口 %d' % (len(wires), len(flags), len(texts), len(ADD_PORT))) if '--push' not in sys.argv: sys.exit(0) print('当前页:', call("return (await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name;")) # ① 元件(已存在就只挪位置) print('元件:', call(""" const LIB='0819f05c4eef4c71ace90d822a990e87'; const spec=%s, have={}; for (const c of await eda.sch_PrimitiveComponent.getAll()) if (c.getState_ComponentType()==='part') have[c.getState_Designator()]=c; const out=[]; for (const [des,uuid,x,y,rot] of spec){ if (have[des]) { await have[des].toAsync().setState_X(x).setState_Y(y).setState_Rotation(rot).done(); out.push(des+' moved'); } else { const c = await eda.sch_PrimitiveComponent.create({libraryUuid:LIB,uuid}, x, y, undefined, rot, false); await c.toAsync().setState_Designator(des).done(); out.push(des+' created'); } } return out;""" % json.dumps([list(p) for p in PARTS]))) # ② 清掉导线 / 旗 / 文字,以及**我加过的那 3 个端口**(原有 14 个端口不动) print('清空:', call(""" let w=0,f=0,t=0,p=0; const mine = %s, mineXY = %s; for (const x of await eda.sch_PrimitiveWire.getAll()){ await eda.sch_PrimitiveWire.delete(x.getState_PrimitiveId()); w++; } for (const c of await eda.sch_PrimitiveComponent.getAll()){ const ty = c.getState_ComponentType(); if (ty==='netflag'){ await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); f++; } else if (ty==='netport'){ const k = Math.round(c.getState_X())+','+Math.round(c.getState_Y()); if (mine.includes(c.getState_Net()) || mineXY.includes(k)){ await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); p++; } } } for (const x of await eda.sch_PrimitiveText.getAll()){ await eda.sch_PrimitiveText.delete(x.getState_PrimitiveId()); t++; } return {wires:w, flags:f, ports:p, texts:t};""" % (json.dumps(sorted({n for n, *_ in ADD_PORT})), json.dumps(['%d,%d' % xy for xy in DROP_PORT_XY])))) n = 0 for part in chunk([[a[0], a[1], b[0], b[1]] for a, b in wires], 40): n += call("for (const s of %s) await eda.sch_PrimitiveWire.create([s[0],s[1],s[2],s[3]]); return %d;" % (json.dumps(part), len(part))) print('导线 %d 段' % n) n = 0 for part in chunk([['Ground' if net == 'GND' else 'Power', net, x, y, r] for net, x, y, r in flags], 25): n += call("for (const f of %s) await eda.sch_PrimitiveComponent.createNetFlag(f[0],f[1],f[2],f[3],f[4],false); return %d;" % (json.dumps(part), len(part))) print('旗 %d 个' % n) n = call("for (const p of %s) await eda.sch_PrimitiveComponent.createNetPort(p[0],p[1],p[2],p[3],p[4],false); return %d;" % (json.dumps([[d, net, x, y, r] for net, x, y, r, d in ADD_PORT]), len(ADD_PORT))) print('端口 %d 个(新增)' % n) n = 0 for part in chunk([[s, x, y, sz] for s, x, y, sz in texts], 20): n += call("for (const t of %s) await eda.sch_PrimitiveText.create(t[1],t[2],t[0],0,null,null,t[3]); return %d;" % (json.dumps(part), len(part))) print('文字 %d 条' % n)