Phase 1: Schematic Workflow Fix (Issue #26) - Fixed broken schematic workflow using template-based symbol cloning - Updated create_project to generate both PCB and schematic files - Rewrote add_schematic_component to use kicad-skip clone() API - Added template schematics with cloneable R, C, LED symbols - All schematic tests now passing Phase 2: JLCPCB Integration Complete - Integrated JLCSearch public API (no authentication required) - Access to ~100k JLCPCB parts with real-time stock and pricing - Implemented parametric search for resistors, capacitors, components - Added package-to-footprint mapping for KiCad integration - Cost optimization with Basic vs Extended library classification - Alternative part suggestions with price comparison New Components: - python/commands/jlcsearch.py - JLCSearch API client - python/templates/ - Template schematics for symbol cloning - docs/JLCPCB_INTEGRATION.md - Comprehensive API documentation - docs/SCHEMATIC_WORKFLOW_FIX.md - Phase 1 technical details - CHANGELOG.md - Consolidated unified changelog - PHASE_2_COMPLETE.md - Phase 2 implementation summary MCP Tools Available: - download_jlcpcb_database - Download full parts catalog - search_jlcpcb_parts - Parametric search with filters - get_jlcpcb_part - Part details + footprint suggestions - get_jlcpcb_database_stats - Database statistics - suggest_jlcpcb_alternatives - Find similar/cheaper parts Technical Improvements: - SQLite database with FTS5 full-text search - HMAC-SHA256 authentication support (official JLCPCB API) - Improved .gitignore to exclude credentials and databases - Template-based schematic creation workflow Testing: - All integration tests passing - Database operations validated - Live API connectivity confirmed - Schematic workflow end-to-end verified Credits: - JLCSearch API: @tscircuit - Local JLCPCB search: @l3wi Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
106 lines
3.9 KiB
Python
106 lines
3.9 KiB
Python
from skip import Schematic
|
|
import os
|
|
import shutil
|
|
import logging
|
|
|
|
logger = logging.getLogger('kicad_interface')
|
|
|
|
class SchematicManager:
|
|
"""Core schematic operations using kicad-skip"""
|
|
|
|
@staticmethod
|
|
def create_schematic(name, metadata=None):
|
|
"""Create a new empty schematic from template"""
|
|
try:
|
|
# Determine template path (use template_with_symbols for component cloning support)
|
|
template_path = os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)),
|
|
'..', 'templates', 'template_with_symbols.kicad_sch'
|
|
)
|
|
|
|
# Determine output path
|
|
output_path = name if name.endswith('.kicad_sch') else f"{name}.kicad_sch"
|
|
|
|
if os.path.exists(template_path):
|
|
# Copy template to target location
|
|
shutil.copy(template_path, output_path)
|
|
logger.info(f"Created schematic from template: {output_path}")
|
|
else:
|
|
# Fallback: create minimal schematic
|
|
logger.warning(f"Template not found at {template_path}, creating minimal schematic")
|
|
with open(output_path, 'w') as f:
|
|
f.write('(kicad_sch (version 20230121) (generator "KiCAD-MCP-Server")\n\n')
|
|
f.write(' (uuid 00000000-0000-0000-0000-000000000000)\n\n')
|
|
f.write(' (paper "A4")\n\n')
|
|
f.write(' (lib_symbols\n )\n\n')
|
|
f.write(' (sheet_instances\n (path "/" (page "1"))\n )\n')
|
|
f.write(')\n')
|
|
|
|
# Load the schematic
|
|
sch = Schematic(output_path)
|
|
logger.info(f"Loaded new schematic: {output_path}")
|
|
return sch
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error creating schematic: {e}")
|
|
raise
|
|
|
|
@staticmethod
|
|
def load_schematic(file_path):
|
|
"""Load an existing schematic"""
|
|
if not os.path.exists(file_path):
|
|
logger.error(f"Schematic file not found at {file_path}")
|
|
return None
|
|
try:
|
|
sch = Schematic(file_path)
|
|
logger.info(f"Loaded schematic from: {file_path}")
|
|
return sch
|
|
except Exception as e:
|
|
logger.error(f"Error loading schematic from {file_path}: {e}")
|
|
return None
|
|
|
|
@staticmethod
|
|
def save_schematic(schematic, file_path):
|
|
"""Save a schematic to file"""
|
|
try:
|
|
# kicad-skip uses write method, not save
|
|
schematic.write(file_path)
|
|
logger.info(f"Saved schematic to: {file_path}")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Error saving schematic to {file_path}: {e}")
|
|
return False
|
|
|
|
@staticmethod
|
|
def get_schematic_metadata(schematic):
|
|
"""Extract metadata from schematic"""
|
|
# kicad-skip doesn't expose a direct metadata object on Schematic.
|
|
# We can return basic info like version and generator.
|
|
metadata = {
|
|
"version": schematic.version,
|
|
"generator": schematic.generator,
|
|
# Add other relevant properties if needed
|
|
}
|
|
logger.debug("Extracted schematic metadata")
|
|
return metadata
|
|
|
|
if __name__ == '__main__':
|
|
# Example Usage (for testing)
|
|
# Create a new schematic
|
|
new_sch = SchematicManager.create_schematic("MyTestSchematic")
|
|
|
|
# Save the schematic
|
|
test_file = "test_schematic.kicad_sch"
|
|
SchematicManager.save_schematic(new_sch, test_file)
|
|
|
|
# Load the schematic
|
|
loaded_sch = SchematicManager.load_schematic(test_file)
|
|
if loaded_sch:
|
|
metadata = SchematicManager.get_schematic_metadata(loaded_sch)
|
|
print(f"Loaded schematic metadata: {metadata}")
|
|
|
|
# Clean up test file
|
|
if os.path.exists(test_file):
|
|
os.remove(test_file)
|
|
print(f"Cleaned up {test_file}")
|