# Schematic Wiring Implementation Plan **Date:** 2026-01-10 **Status:** Planning Phase **Priority:** HIGH (User-requested feature for Issue #26) --- ## Executive Summary This plan outlines the implementation of complete schematic wiring functionality for the KiCAD MCP Server. Currently, component placement works perfectly with dynamic symbol loading, but wire/connection tools are incomplete or non-functional. **Goal:** Enable users to create complete, functional schematics with wired connections between components through the MCP interface. --- ## Current State Analysis ### What Exists ✅ **Files:** - `python/commands/connection_schematic.py` - ConnectionManager class with wire/label methods - MCP handlers in `kicad_interface.py` for 6 connection-related tools **MCP Tools (Registered):** 1. `add_schematic_wire` - Add wire between two points 2. `add_schematic_connection` - Connect two component pins 3. `add_schematic_net_label` - Add net label 4. `connect_to_net` - Connect pin to named net 5. `get_net_connections` - Query net connections 6. `generate_netlist` - Generate netlist from schematic **ConnectionManager Methods:** - `add_wire(schematic, start_point, end_point)` - Add wire between coordinates - `add_connection(schematic, source_ref, source_pin, target_ref, target_pin)` - Connect pins - `add_net_label(schematic, net_name, position)` - Add label - `connect_to_net(schematic, component_ref, pin_name, net_name)` - Pin to net - `get_pin_location(symbol, pin_name)` - Get pin coordinates - `get_net_connections(schematic, net_name)` - Query connections - `generate_netlist(schematic)` - Generate netlist ### What's Broken/Missing ❌ **Problem 1: kicad-skip API Uncertainty** - Code assumes `schematic.wire.append()` exists - Code assumes `schematic.label.append()` exists - Code assumes pins have `.name` and `.location` attributes - **Need to verify what kicad-skip actually supports** **Problem 2: Pin Location Calculation** - Current implementation tries to calculate absolute pin positions - May not account for symbol rotation - May not work with multi-unit symbols - Pin numbering vs pin naming confusion **Problem 3: No Visual Feedback** - No way to verify wires were created correctly - No validation of wire endpoints - No checks for overlapping wires or junctions **Problem 4: Limited Testing** - No integration tests for wiring functionality - No validation with real KiCad schematics - User reported `add_schematic_wire` fails **Problem 5: Missing Features** - No junction (wire intersection) support - No bus support (multi-bit signals) - No no-connect flags - No power symbols (VCC, GND graphical symbols) - No hierarchical labels --- ## Technical Challenges ### Challenge 1: kicad-skip Wire API **Issue:** The kicad-skip library documentation is sparse. We need to determine: - Does `schematic.wire` exist? - What's the correct API to add wires? - How are wires stored in .kicad_sch files? **S-Expression Format (KiCad 8/9):** ```lisp (wire (pts (xy 100 100) (xy 200 100)) (stroke (width 0) (type default)) (uuid "12345678-1234-1234-1234-123456789012") ) ``` **Approach:** 1. Examine kicad-skip source code 2. Test wire creation manually with kicad-skip 3. Fall back to S-expression manipulation if necessary (similar to dynamic symbol loading) ### Challenge 2: Pin Location Discovery **Issue:** Need to find exact pin coordinates for automatic wiring. **Pin Data in Symbols:** Pins are defined within symbol definitions in lib_symbols, with coordinates relative to symbol origin. When symbol is placed, pins move with it. **Required Information:** - Symbol position (x, y) - Symbol rotation angle - Pin offset from symbol origin - Pin number/name mapping **Solution:** 1. Parse symbol definition to find pin definitions 2. Apply transformation matrix (position + rotation) to pin coordinates 3. Return absolute pin position in schematic space ### Challenge 3: Smart Wire Routing **Issue:** Users don't want to manually specify every wire segment. **Desired Behavior:** ``` User: "Connect R1 pin 1 to C1 pin 1" System: - Calculate R1 pin 1 location: (100, 100) - Calculate C1 pin 1 location: (150, 120) - Create wire path (orthogonal routing preferred): - (100, 100) → (100, 120) → (150, 120) - Or simple direct: (100, 100) → (150, 120) ``` **Auto-Routing Options:** 1. **Direct** - Single wire segment (diagonal if needed) 2. **Orthogonal** - Only horizontal/vertical segments (2 segments) 3. **Manhattan** - Complex path avoiding components (3+ segments) **Phase 1 Approach:** Start with direct wiring, add orthogonal later. ### Challenge 4: Net Label Integration **Issue:** Labels need to attach to wires, not float in space. **KiCad Behavior:** - Labels must touch a wire or pin - Labels create electrical connections at their attachment point - Multiple labels with same name = connected net **Implementation:** - When adding label, find nearest wire endpoint - Attach label to that coordinate - Or create short wire stub for label attachment --- ## Implementation Phases ### Phase 1: Core Wire Functionality (Week 1) **Goal:** Get basic wiring working with kicad-skip API **Tasks:** 1. **Research kicad-skip Wire API** (4 hours) - Read kicad-skip source code - Test wire creation with Python REPL - Document actual API methods - Create test schematic with manual wires 2. **Fix Wire Creation** (6 hours) - Update ConnectionManager.add_wire() with correct API - Handle S-expression manipulation if needed - Add UUID generation for wires - Test with simple wire (100,100) → (200,100) 3. **Implement Pin Discovery** (8 hours) - Parse symbol definitions to extract pin data - Handle pin coordinates relative to symbol - Apply rotation transformation - Test with R, C, LED from dynamic symbols 4. **Fix add_schematic_connection** (4 hours) - Use correct pin discovery - Create direct wire between pins - Handle error cases (pin not found, etc.) - Test with R1 pin 2 → C1 pin 1 5. **Integration Testing** (4 hours) - Create test schematic with R, C, LED - Wire R to C - Wire C to LED - Verify schematic opens in KiCad - Verify electrical connectivity **Deliverables:** - Working `add_schematic_wire` tool - Working `add_schematic_connection` tool - Pin location discovery working - Integration test passing - Documentation updated **Success Criteria:** - User can connect two resistor pins with MCP command - Wire appears in KiCad schematic viewer - Netlist shows electrical connection --- ### Phase 2: Net Labels & Named Nets (Week 1-2) **Goal:** Enable named net connections (VCC, GND, etc.) **Tasks:** 1. **Fix Net Label Creation** (4 hours) - Update ConnectionManager.add_net_label() - Use correct kicad-skip API or S-expression - Position labels correctly - Test label creation 2. **Implement connect_to_net** (6 hours) - Create wire stub from pin - Attach label to wire endpoint - Support common nets (VCC, GND, 3V3, etc.) - Test with multiple components on same net 3. **Net Connection Discovery** (6 hours) - Parse wires and labels in schematic - Build connectivity graph - Implement get_net_connections() - Return all pins on a net 4. **Power Symbol Support** (8 hours) - Add power symbols to templates (VCC, GND, 3V3, 5V) - Or dynamically load from power library - Connect power pins to power nets - Test complete circuit with power 5. **Testing** (4 hours) - Create circuit with VCC, GND nets - Connect multiple components to each net - Verify net connectivity - Generate and validate netlist **Deliverables:** - Working `add_schematic_net_label` tool - Working `connect_to_net` tool - Working `get_net_connections` tool - Power symbol support - Netlist generation working **Success Criteria:** - User can label nets VCC, GND - Multiple components connect to same net - Netlist correctly shows net membership --- ### Phase 3: Advanced Features (Week 2-3) **Goal:** Professional schematic features **Tasks:** 1. **Junction Support** (4 hours) - Detect wire intersections - Add junction dots at T-junctions - S-expression: `(junction (at x y) (diameter 0) (uuid ...))` 2. **No-Connect Flags** (2 hours) - Add "X" marks on unused pins - S-expression: `(no_connect (at x y) (uuid ...))` 3. **Orthogonal Routing** (6 hours) - Implement 2-segment wire routing - Horizontal-then-vertical or vertical-then-horizontal - Choose best path based on pin positions 4. **Bus Support** (8 hours) - Multi-bit signal buses - Bus labels (e.g., "D[0..7]") - Bus entries for individual signals 5. **Hierarchical Labels** (8 hours) - Labels for hierarchical sheets - Input/Output/Bidirectional types - Sheet connections **Deliverables:** - Junction creation - No-connect support - Smart orthogonal routing - Bus and hierarchical label support **Success Criteria:** - Wires route cleanly around components - Junctions appear at wire intersections - Unused pins marked with no-connect --- ### Phase 4: Validation & Polish (Week 3-4) **Goal:** Production-ready reliability **Tasks:** 1. **ERC Integration** (6 hours) - Electrical Rule Check - Detect floating nets - Detect unconnected pins - Detect short circuits 2. **Visual Validation** (4 hours) - Export schematic to PDF after wiring - Verify wire appearance - Check net label placement 3. **Comprehensive Testing** (8 hours) - Test with Device library components - Test with IC components (multi-pin) - Test with connectors - Test complex circuits (10+ components) 4. **Error Handling** (4 hours) - Graceful failures - Clear error messages - Validation of coordinates - Duplicate net label detection 5. **Documentation** (6 hours) - Update MCP tool descriptions - Add usage examples to README - Create wiring tutorial - Add to CHANGELOG **Deliverables:** - ERC validation - Comprehensive test suite - Error handling - Complete documentation **Success Criteria:** - 95%+ test pass rate - Users can create functional circuits - Clear error messages on failures --- ## Technical Approach ### Option A: Use kicad-skip Native API (Preferred) **If kicad-skip supports wires natively:** ```python # Add wire using native API wire = schematic.wire.new( start=[100, 100], end=[200, 100] ) # Add label label = schematic.label.new( text="VCC", at=[150, 100] ) ``` **Pros:** - Clean, maintainable code - Follows library patterns - Less likely to break **Cons:** - Depends on kicad-skip having these features - May be limited in functionality ### Option B: S-Expression Manipulation (Fallback) **If kicad-skip doesn't support wires:** Use the same approach as dynamic symbol loading: ```python import sexpdata from sexpdata import Symbol # Read schematic with open(schematic_path, 'r') as f: sch_data = sexpdata.loads(f.read()) # Create wire S-expression wire_sexp = [ Symbol('wire'), [Symbol('pts'), [Symbol('xy'), 100, 100], [Symbol('xy'), 200, 100] ], [Symbol('stroke'), [Symbol('width'), 0], [Symbol('type'), Symbol('default')]], [Symbol('uuid'), str(uuid.uuid4())] ] # Insert into schematic sch_data.append(wire_sexp) # Write back with open(schematic_path, 'w') as f: f.write(sexpdata.dumps(sch_data)) ``` **Pros:** - Complete control - Can implement any feature - Works around library limitations **Cons:** - More complex - Requires deep KiCad format knowledge - More maintenance ### Hybrid Approach (Recommended) 1. Try kicad-skip native API first 2. Fall back to S-expression if needed 3. Use S-expression for advanced features (junctions, buses) --- ## Pin Discovery Algorithm ### Step 1: Get Symbol Definition Symbols are stored in `lib_symbols` section: ```lisp (lib_symbols (symbol "Device:R" (symbol "R_0_1" (rectangle (start -1 -2.54) (end 1 2.54) ...)) (symbol "R_1_1" (pin passive line (at 0 3.81 270) (length 1.27) (name "~" (effects (font (size 1.27 1.27)))) (number "1" (effects (font (size 1.27 1.27))))) (pin passive line (at 0 -3.81 90) (length 1.27) (name "~" (effects (font (size 1.27 1.27)))) (number "2" (effects (font (size 1.27 1.27))))))) ``` ### Step 2: Extract Pin Information For each pin: - Number (e.g., "1", "2") - Name (e.g., "GND", "VCC", "~" for unnamed) - Position relative to symbol origin: `(at x y angle)` - Length (distance from symbol body to connection point) ### Step 3: Get Symbol Instance Position From symbol instance in schematic: ```lisp (symbol (lib_id "Device:R") (at 100 100 0) (unit 1) (property "Reference" "R1" ...)) ``` Extract: - Position: `(at 100 100 0)` = x=100, y=100, rotation=0° - Reference: "R1" ### Step 4: Calculate Absolute Pin Position ```python def get_absolute_pin_position(symbol_instance, pin_definition): # Symbol position symbol_x, symbol_y, symbol_rotation = symbol_instance.at.value # Pin position relative to symbol pin_x, pin_y, pin_angle = pin_definition.at.value # Apply rotation transformation if symbol_rotation != 0: # Rotate pin coordinates around origin rad = math.radians(symbol_rotation) rotated_x = pin_x * math.cos(rad) - pin_y * math.sin(rad) rotated_y = pin_x * math.sin(rad) + pin_y * math.cos(rad) pin_x, pin_y = rotated_x, rotated_y # Translate to absolute position abs_x = symbol_x + pin_x abs_y = symbol_y + pin_y return [abs_x, abs_y] ``` --- ## Wire Routing Strategies ### Strategy 1: Direct Wire (Phase 1) Simplest: single wire segment from pin A to pin B. ``` R1 pin 2 C1 pin 1 o-------------o ``` **Pros:** Simple, fast **Cons:** Diagonal wires (not standard practice) ### Strategy 2: Orthogonal 2-Segment (Phase 3) Two segments: horizontal then vertical, or vertical then horizontal. ``` R1 pin 2 C1 pin 1 o-----┐ │ └------o ``` **Algorithm:** 1. Calculate midpoint 2. Route horizontal to midpoint 3. Route vertical to target 4. Or vice versa based on direction **Pros:** Standard practice, cleaner schematics **Cons:** Slightly more complex ### Strategy 3: Manhattan Routing (Future) Complex multi-segment paths avoiding components. **Pros:** Professional appearance **Cons:** Requires collision detection, path planning --- ## Testing Strategy ### Unit Tests Test individual functions: - `test_add_wire()` - Wire creation - `test_get_pin_location()` - Pin discovery - `test_add_net_label()` - Label creation - `test_calculate_pin_position()` - Coordinate math ### Integration Tests Test complete workflows: - `test_connect_two_resistors()` - Wire R1 to R2 - `test_connect_to_vcc_net()` - Multiple components to VCC - `test_generate_netlist()` - Netlist accuracy - `test_schematic_opens_in_kicad()` - File validity ### Manual Validation - Create test schematic in KiCad manually - Add same connections via MCP - Compare results - Verify electrical connectivity in KiCad --- ## Success Metrics ### Phase 1 Success: - [ ] `add_schematic_wire` works (coordinates) - [ ] `add_schematic_connection` works (pin to pin) - [ ] Wires appear in KiCad schematic - [ ] Netlist shows connections - [ ] 3+ integration tests passing ### Phase 2 Success: - [ ] Net labels work (VCC, GND, etc.) - [ ] Multiple components on same net - [ ] `get_net_connections` returns correct results - [ ] Netlist includes named nets - [ ] 5+ integration tests passing ### Phase 3 Success: - [ ] Junctions at wire intersections - [ ] Orthogonal routing preferred - [ ] No-connect flags on unused pins - [ ] 10+ integration tests passing ### Phase 4 Success: - [ ] ERC detects errors - [ ] 95%+ test coverage - [ ] Complete documentation - [ ] User can create functional circuits without errors --- ## Risk Assessment | Risk | Probability | Impact | Mitigation | |------|------------|--------|------------| | kicad-skip lacks wire API | High | High | Use S-expression fallback | | Pin discovery complex | Medium | Medium | Test with multiple symbol types | | Rotation math errors | Medium | High | Extensive testing, validation | | Performance issues | Low | Medium | Optimize S-expression parsing | | KiCad format changes | Low | High | Version detection, compatibility | --- ## Dependencies **Required:** - kicad-skip >= 0.1.0 (or compatible) - sexpdata (already dependency for dynamic loading) - Python 3.8+ **Optional:** - KiCad CLI for validation (`kicad-cli sch export netlist`) --- ## Timeline Estimate **Phase 1:** 1 week (26 hours) **Phase 2:** 1 week (28 hours) **Phase 3:** 1.5 weeks (28 hours) **Phase 4:** 1.5 weeks (28 hours) **Total:** 5 weeks (110 hours) **Accelerated path (core features only):** 2-3 weeks (Phases 1-2) --- ## Next Immediate Steps 1. **Research kicad-skip Wire API** (TODAY) - Test with Python REPL - Document findings - Choose implementation approach 2. **Create Test Environment** (TOMORROW) - Set up test schematic - Manual wire creation in KiCad - Export for comparison 3. **Implement Basic Wire** (THIS WEEK) - Update ConnectionManager.add_wire() - Test with simple coordinates - Verify in KiCad 4. **Fix Pin Discovery** (THIS WEEK) - Parse symbol definitions - Calculate absolute positions - Test with rotated symbols --- ## User Communication **For Issue #26:** Update users that: - ✅ Component placement is DONE (with 10,000+ symbols) - ⏳ Wire/connection tools are IN PROGRESS - 📅 Estimated completion: 2-3 weeks for core functionality - 🎯 Goal: Complete functional schematics with wiring --- **Status:** Ready for implementation **Owner:** TBD **Priority:** HIGH (user-blocking feature)