文件
phonerail/.claude/pcb1_dcjack.py
T

189 行
8.1 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""下板 PCB1:把 `J1` 从 XT30PW-M 换成圆形 DC 电源座 DC-005-5.5*2.5。**不走导入对话框。**
/c/Python314/python .claude/pcb1_dcjack.py # 干跑
/c/Python314/python .claude/pcb1_dcjack.py --push # 换件 + 接网络 + 存盘 + 回查
换完再跑 `pcb1_place.py --push` 把它摆到位(本脚本只负责"换成哪个件、接哪几个网")。
## ⛔ 为什么绕开「从原理图导入变更」
2026-09-08 实测:那个对话框对下板已经**不能用**了。它提出的变更是一大串风扇块
重映射(`J27→J26`、`Q10→Q9`、`R753→R752`、`Q7` 换成 4 脚座封装…),
而下板和原理图**按四项逐个对过、全部一致**:
| 对账项 | 结果 |
|---|---|
| 位号(301 个)| 全对 |
| 封装名 | 只有 J1 一处不同(就是本脚本要改的)|
| 器件值(风扇块 23 件)| 全对 |
| 焊盘网络(风扇块)| 全对,且自洽(J26→`FAN_IN_TACH_RAW`→R750/751/752→Q9→`FAN_TACH_IN`)|
根因是 skill §9o:**P6-FAN-EDL 页整页重画过,通道 ID 全变了**,
EasyEDA 按内部 ID 重新配对,配错了一格。应用下去会把一个本来正确的风扇块打乱。
⇒ 这块板上「改一颗件的封装」只能定点做。代价是这颗件与原理图的内部 ID 链接断了,
以后导入对话框会报它 —— 但那个对话框对这块板本来就已经不可用。
## 为什么不能用 `pcb_PrimitiveComponent.modify()`
读过它的实现:只处理 `layer / x / y / rotation / primitiveLock / otherProperty`
和位号那一组属性,**没有 `setState_Footprint`**。换封装只能删了重建。
## `pcb_PrimitiveComponent.create()` 的签名(实测)
```
create(器件{libraryUuid,uuid}, layer, x, y, rotation, ?)
```
⚠️ **第二个参数是层,不是 x** —— 按 `(dev, x, y, rot, layer)` 传的话,
x 会被当成层号写进去(实测读回 `layer: 10236.22`),而元件落在 (0,0) 附近,
`getAll()` 数量对得上、看着像成功了。
## 引脚与接法(依据见 `p1_dcjack.py` 文件头)
pin1 = 中心正极 → 原 J1 的 `+` 那个网络;pin2 / pin3 = 两个负极触点 → 都接 GND。
**网络名不写死**,从被删掉的那颗 J1 身上读,避免自动命名网改名之后接错。
"""
import io
import json
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
from eda import run
PCB = '7e9415a16a909c51'
MIL = 39.3700787
# 工程库里的 DC-005-5.5*2.5(原理图放上去时 EasyEDA 自己复制进来的)
DEV = {'libraryUuid': '1e5745f4caff4b15a921694d2fd912e4', 'uuid': '82b5a3c78e8ab633'}
FP_NAME = 'DC-IN-TH_DC-005-2'
# 摆位交给 pcb1_place.py,这里只要一个不碍事的落脚点(板外)
DROP_X, DROP_Y = 240.0, 40.0
# 旧 J1(XT30)的引脚 → 新 J1(DC-005)的引脚
# 旧 pin2 = '+' → 新 pin1(中心正极)
# 旧 pin1 = '−' → 新 pin2 + pin3(两个负极触点并联,见 p1_dcjack.py)
# 旧 pin3/pin4 是 XT30 的固定脚,DC-005 没有对应物
MAP = {'1': '2', '2': '1', '3': '1'} # 新引脚号 -> 从旧的哪个引脚取网络
def call(js, timeout=300):
r = run(js, timeout=timeout)
if not r.get('success'):
raise RuntimeError(json.dumps(r, ensure_ascii=False)[:1200])
return r['result']
JS_SURVEY = u"""
await eda.dmt_EditorControl.openDocument('%s');
await new Promise(r => setTimeout(r, 2000));
const MIL = %f;
const comps = await eda.pcb_PrimitiveComponent.getAll();
const out = {n: comps.length, j1: null, strays: []};
for (const c of comps) {
const d = c.getState_Designator();
const fp = (c.getState_Footprint() || {}).name;
if (d === 'J1') {
const pins = {};
for (const p of await c.getAllPins())
pins[p.getState_PadNumber()] = {net: p.getState_Net(), pid: p.getState_PrimitiveId()};
out.j1 = {pid: c.getState_PrimitiveId(), fp, dev: (c.getState_Component() || {}).name,
x: c.getState_X() / MIL, y: c.getState_Y() / MIL, rot: c.getState_Rotation(), pins};
} else if (fp === '%s') {
// 试签名时留下的临时件(位号会是 DC1 之类)
out.strays.push({pid: c.getState_PrimitiveId(), des: d, x: c.getState_X() / MIL, y: c.getState_Y() / MIL});
}
}
return out;
""" % (PCB, MIL, FP_NAME)
def main():
push = '--push' in sys.argv
s = call(JS_SURVEY)
print(u'板上元件 %d 个' % s['n'])
j1 = s['j1']
if not j1:
sys.exit(u'⛔ 板上没有 J1')
print(u'J1 %s / %s (%.2f, %.2f) rot %s' % (j1['dev'], j1['fp'], j1['x'], j1['y'], j1['rot']))
for n in sorted(j1['pins']):
print(u' pin%-2s net=%s' % (n, j1['pins'][n]['net'] or '(空)'))
if s['strays']:
print(u'临时残留 DC-005 %d 个(会一并删掉):%s'
% (len(s['strays']), ', '.join('%s@(%.0f,%.0f)' % (t['des'], t['x'], t['y']) for t in s['strays'])))
if j1['fp'] == FP_NAME:
print(u'\nJ1 已经是 %s,无需再换。' % FP_NAME)
return
want = {}
for new_pin, old_pin in sorted(MAP.items()):
net = (j1['pins'].get(old_pin) or {}).get('net') or ''
if not net:
sys.exit(u'⛔ 旧 J1 的 pin%s 没有网络 —— 先查清楚再换' % old_pin)
want[new_pin] = net
print(u'\n新 J1 的接法(网络名从旧件读,不写死):')
for n in sorted(want):
print(u' pin%-2s <- 旧 pin%-2s net=%s' % (n, MAP[n], want[n]))
assert want['2'] == want['3'], u'⛔ 两个负极触点应该同网(都是旧件的 −),实得 %s / %s' % (want['2'], want['3'])
if not push:
print(u'\n加 --push 执行')
return
r = call(u"""
await eda.dmt_EditorControl.openDocument('%s');
await new Promise(r => setTimeout(r, 2000));
const MIL = %f, DEV = %s, WANT = %s;
const before = (await eda.pcb_PrimitiveComponent.getAll()).length;
// 1) 删掉旧 J1 和试签名留下的临时件
for (const id of %s) await eda.pcb_PrimitiveComponent.delete(id);
// 2) 建新件。⚠️ 签名是 (器件, layer, x, y, rotation, ?)
const c = await eda.pcb_PrimitiveComponent.create(DEV, 1, %f * MIL, %f * MIL, 0, undefined);
const pid = c.getState_PrimitiveId();
await eda.pcb_PrimitiveComponent.modify(pid, {}); // 拿一个同步句柄
const k = (await eda.pcb_PrimitiveComponent.getAll()).find(x => x.getState_PrimitiveId() === pid);
k.toAsync().setState_Designator('J1').done();
// 3) 接网络
const done = {};
for (const p of await k.getAllPins()) {
const n = p.getState_PadNumber();
if (WANT[n] === undefined) continue;
p.toAsync().setState_Net(WANT[n]).done();
done[n] = WANT[n];
}
const after = (await eda.pcb_PrimitiveComponent.getAll()).length;
return {before, after, pid, done};
""" % (PCB, MIL, json.dumps(DEV), json.dumps(want),
json.dumps([j1['pid']] + [t['pid'] for t in s['strays']]),
DROP_X, DROP_Y))
print(u'\n元件数 %d -> %d,新 J1 = %s,接网络 %s' % (r['before'], r['after'], r['pid'], r['done']))
call(u"await eda.dmt_EditorControl.openDocument('%s'); await new Promise(r=>setTimeout(r,1500));"
u"return await eda.pcb_Document.save();" % PCB)
# §9ad:save() 说成功不算数,重新读一遍才算
b = call(JS_SURVEY)
nj = b['j1']
if not nj:
sys.exit(u'⛔ 回查读不到 J1')
print(u'\n回查 J1:%s / %s (%.2f, %.2f) rot %s'
% (nj['dev'], nj['fp'], nj['x'], nj['y'], nj['rot']))
assert nj['fp'] == FP_NAME, u'⛔ 封装没换成: %s' % nj['fp']
for n in sorted(want):
got = (nj['pins'].get(n) or {}).get('net')
print(u' pin%-2s net=%s' % (n, got or '(空)'))
assert got == want[n], u'⛔ pin%s 网络是 %s,应该是 %s' % (n, got, want[n])
assert b['n'] == s['n'] - len(s['strays']), \
u'⛔ 元件数 %d,应该是 %d' % (b['n'], s['n'] - len(s['strays']))
assert not b['strays'], u'⛔ 还有临时件没删干净'
print(u' ✔ 封装 / 三个引脚网络 / 元件数 全部回查通过')
print(u'\n接着跑:pcb1_place.py --push(把它摆到西板边)')
if __name__ == '__main__':
main()