kicad:EasyEDA→KiCad 工程(Board1/Board2)、库、脚本与评审文档(IC 引脚、风扇、热、EDL 供电、布局规则)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
zhou yang
2026-10-04 19:24:42 +08:00
共同撰写人 Claude Opus 5.5
父节点 1d842cf45f
当前提交 bfe094a5d7
共修改 173 个文件,包含 401864 行新增和 0 行删除
+95
查看文件
@@ -0,0 +1,95 @@
"""Read the live EasyEDA component catalog through the installed API bridge.
Archive exact device-search and device-detail responses for fan selection.
This does not edit the EasyEDA project or claim that catalog entries are stocked.
"""
import argparse
from datetime import datetime, timezone
import json
from pathlib import Path
import sys
import requests
ROOT = Path(__file__).resolve().parents[1]
def bridge(session):
for port in range(49620, 49630):
base = f'http://127.0.0.1:{port}'
try:
response = session.get(base + '/health', timeout=.5)
health = response.json()
except (requests.RequestException, ValueError):
continue
if health.get('service') == 'easyeda-bridge':
return base, health
raise RuntimeError('Installed EasyEDA API bridge not reachable on 49620-49629')
def main():
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest='action', required=True)
sub.add_parser('probe')
search = sub.add_parser('search')
search.add_argument('keywords', nargs='+')
search.add_argument('--page', type=int, default=1)
search.add_argument('--limit', type=int, default=100)
search.add_argument('--category', nargs=2, metavar=('PRIMARY_UUID', 'SECONDARY_UUID'))
detail = sub.add_parser('detail')
detail.add_argument('uuid')
detail.add_argument('--library')
args = parser.parse_args()
session = requests.Session()
session.trust_env = False
base, health = bridge(session)
if args.action == 'probe':
print(json.dumps(health, ensure_ascii=False, indent=2))
return 0 if health.get('edaConnected') else 2
if not health.get('edaConnected'):
raise RuntimeError('Bridge is healthy but no EasyEDA API Gateway window is connected')
# Reading the public catalog does not require selecting or editing a project.
window = health.get('activeWindowId')
if not window:
raise RuntimeError('No active EasyEDA window; select a client window first')
if args.action == 'search':
assert 1 <= args.limit <= 100 and args.page >= 1
category = json.dumps({'libraryUuid': '0819f05c4eef4c71ace90d822a990e87', 'libraryType': '3',
'primaryClassificationUuid': args.category[0],
'secondaryClassificationUuid': args.category[1]}) if args.category else 'undefined'
queries = [(key, 'return await eda.lib_Device.search(' + json.dumps('' if key == '*' else key) +
f', undefined, {category}, undefined, {args.limit}, {args.page});') for key in args.keywords]
else:
queries = [(args.uuid, 'return await eda.lib_Device.get(' + json.dumps(args.uuid) +
', ' + (json.dumps(args.library) if args.library else 'undefined') + ');')]
output = ROOT/'out/fan-catalog'
output.mkdir(exist_ok=True)
for query, code in queries:
response = session.post(base+'/execute', json={'code': code, 'windowId': window}, timeout=40)
response.raise_for_status()
result = response.json()
if result.get('success') is False or result.get('error'):
raise RuntimeError(str(result))
timestamp = datetime.now(timezone.utc)
record = {'retrieved_at_utc': timestamp.isoformat(), 'source': 'Live EasyEDA lib_Device API',
'window_id': window, 'operation': args.action, 'query': query,
'page': getattr(args, 'page', None), 'category': getattr(args, 'category', None), 'response': result}
path = output/(timestamp.strftime('%Y%m%dT%H%M%S%f')+'-'+args.action+'.json')
path.write_text(json.dumps(record, indent=2, ensure_ascii=False)+'\n', encoding='utf-8')
print(path.relative_to(ROOT))
data = result.get('result')
if isinstance(data, list):
print('Results:', len(data), flush=True)
for part in data:
print(json.dumps({k: part.get(k) for k in ['name', 'uuid', 'supplierId', 'description']}, ensure_ascii=False), flush=True)
else:
print(json.dumps(data, ensure_ascii=False), flush=True)
return 0
if __name__ == '__main__':
try:
raise SystemExit(main())
except (RuntimeError, requests.RequestException) as exc:
print(str(exc), file=sys.stderr)
raise SystemExit(2)