feat: Extend IPC backend with 21 commands and hybrid footprint placement
- Add IPC handlers for zone operations (add_copper_pour, refill_zones) - Add IPC handlers for board operations (add_board_outline, add_mounting_hole, get_layer_list) - Add IPC handlers for component operations (rotate_component, get_component_properties) - Add IPC handlers for net operations (delete_trace, get_nets_list) - Implement hybrid footprint placement (SWIG library loading + IPC placement) - Extend create_schematic to handle filename, title, projectName params - Update documentation for IPC backend status and known issues 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
45
README.md
45
README.md
@@ -4,18 +4,27 @@ A Model Context Protocol (MCP) server that enables AI assistants like Claude to
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard from Anthropic that allows AI assistants to securely connect to external tools and data sources. This implementation provides a standardized bridge between AI assistants and KiCAD, enabling natural language control of professional PCB design operations.
|
The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard from Anthropic that allows AI assistants to securely connect to external tools and data sources. This implementation provides a standardized bridge between AI assistants and KiCAD, enabling natural language control of PCB design operations.
|
||||||
|
|
||||||
**Key Capabilities:**
|
**Key Capabilities:**
|
||||||
- 52 fully-documented tools with JSON Schema validation
|
- 52 fully-documented tools with JSON Schema validation
|
||||||
- 8 dynamic resources exposing project state
|
- 8 dynamic resources exposing project state
|
||||||
- Full MCP 2025-06-18 protocol compliance
|
- Full MCP 2025-06-18 protocol compliance
|
||||||
- Cross-platform support (Linux, Windows, macOS)
|
- Cross-platform support (Linux, Windows, macOS)
|
||||||
- Real-time KiCAD UI integration
|
- Real-time KiCAD UI integration via IPC API (experimental)
|
||||||
- Comprehensive error handling and logging
|
- Comprehensive error handling and logging
|
||||||
|
|
||||||
## What's New in v2.1.0
|
## What's New in v2.1.0
|
||||||
|
|
||||||
|
### IPC Backend (Experimental)
|
||||||
|
We are currently implementing and testing the KiCAD 9.0 IPC API for real-time UI synchronization:
|
||||||
|
- Changes made via MCP tools appear immediately in the KiCAD UI
|
||||||
|
- No manual reload required when IPC is active
|
||||||
|
- Hybrid backend: uses IPC when available, falls back to SWIG API
|
||||||
|
- 20+ commands now support IPC including routing, component placement, and zone operations
|
||||||
|
|
||||||
|
Note: IPC features are under active development and testing. Enable IPC in KiCAD via Preferences > Plugins > Enable IPC API Server.
|
||||||
|
|
||||||
### Comprehensive Tool Schemas
|
### Comprehensive Tool Schemas
|
||||||
Every tool now includes complete JSON Schema definitions with:
|
Every tool now includes complete JSON Schema definitions with:
|
||||||
- Detailed parameter descriptions and constraints
|
- Detailed parameter descriptions and constraints
|
||||||
@@ -134,6 +143,7 @@ The server provides 52 tools organized into functional categories:
|
|||||||
**Python 3.10 or Higher**
|
**Python 3.10 or Higher**
|
||||||
- Usually included with KiCAD
|
- Usually included with KiCAD
|
||||||
- Required packages (auto-installed):
|
- Required packages (auto-installed):
|
||||||
|
- kicad-python (kipy) >= 0.5.0 (IPC API support, optional but recommended)
|
||||||
- kicad-skip >= 0.1.0 (schematic support)
|
- kicad-skip >= 0.1.0 (schematic support)
|
||||||
- Pillow >= 9.0.0 (image processing)
|
- Pillow >= 9.0.0 (image processing)
|
||||||
- cairosvg >= 2.7.0 (SVG rendering)
|
- cairosvg >= 2.7.0 (SVG rendering)
|
||||||
@@ -314,7 +324,12 @@ List all electrical nets.
|
|||||||
- Provides logging and error recovery
|
- Provides logging and error recovery
|
||||||
|
|
||||||
### Python Interface (`python/`)
|
### Python Interface (`python/`)
|
||||||
- **kicad_interface.py:** Main entry point, MCP message handler
|
- **kicad_interface.py:** Main entry point, MCP message handler, command routing
|
||||||
|
- **kicad_api/:** Backend implementations
|
||||||
|
- `base.py` - Abstract base classes for backends
|
||||||
|
- `ipc_backend.py` - KiCAD 9.0 IPC API backend (real-time UI sync)
|
||||||
|
- `swig_backend.py` - pcbnew SWIG API backend (file-based operations)
|
||||||
|
- `factory.py` - Backend auto-detection and instantiation
|
||||||
- **schemas/tool_schemas.py:** JSON Schema definitions for all tools
|
- **schemas/tool_schemas.py:** JSON Schema definitions for all tools
|
||||||
- **resources/resource_definitions.py:** Resource handlers and URIs
|
- **resources/resource_definitions.py:** Resource handlers and URIs
|
||||||
- **commands/:** Modular command implementations
|
- **commands/:** Modular command implementations
|
||||||
@@ -328,7 +343,9 @@ List all electrical nets.
|
|||||||
- `library.py` - Footprint libraries
|
- `library.py` - Footprint libraries
|
||||||
|
|
||||||
### KiCAD Integration
|
### KiCAD Integration
|
||||||
- **pcbnew API:** Direct Python bindings to KiCAD
|
- **pcbnew API (SWIG):** Direct Python bindings to KiCAD for file operations
|
||||||
|
- **IPC API (kipy):** Real-time communication with running KiCAD instance (experimental)
|
||||||
|
- **Hybrid Backend:** Automatically uses IPC when available, falls back to SWIG
|
||||||
- **kicad-skip:** Schematic file manipulation
|
- **kicad-skip:** Schematic file manipulation
|
||||||
- **Platform Detection:** Cross-platform path handling
|
- **Platform Detection:** Cross-platform path handling
|
||||||
- **UI Management:** Automatic KiCAD UI launch/detection
|
- **UI Management:** Automatic KiCAD UI launch/detection
|
||||||
@@ -428,11 +445,11 @@ npm run format
|
|||||||
|
|
||||||
**Current Version:** 2.1.0-alpha
|
**Current Version:** 2.1.0-alpha
|
||||||
|
|
||||||
**Production-Ready Features:**
|
**Working Features:**
|
||||||
- Project creation and management
|
- Project creation and management
|
||||||
- Board outline and sizing
|
- Board outline and sizing
|
||||||
- Layer management
|
- Layer management
|
||||||
- Component placement (with library integration needed)
|
- Component placement with footprint library loading
|
||||||
- Mounting holes and text annotations
|
- Mounting holes and text annotations
|
||||||
- Design rule checking
|
- Design rule checking
|
||||||
- Export to Gerber, PDF, SVG, 3D
|
- Export to Gerber, PDF, SVG, 3D
|
||||||
@@ -440,19 +457,21 @@ npm run format
|
|||||||
- UI auto-launch
|
- UI auto-launch
|
||||||
- Full MCP protocol compliance
|
- Full MCP protocol compliance
|
||||||
|
|
||||||
**In Development:**
|
**Under Active Development (IPC Backend):**
|
||||||
|
- Real-time UI synchronization via KiCAD 9.0 IPC API
|
||||||
|
- IPC-enabled commands: route_trace, add_via, place_component, move_component, delete_component, add_copper_pour, refill_zones, add_board_outline, add_mounting_hole, and more
|
||||||
|
- Hybrid footprint loading (SWIG for library access, IPC for placement)
|
||||||
|
- Zone/copper pour support via IPC
|
||||||
|
|
||||||
|
Note: IPC features are experimental and under testing. Some commands may not work as expected in all scenarios.
|
||||||
|
|
||||||
|
**Planned:**
|
||||||
- JLCPCB parts integration
|
- JLCPCB parts integration
|
||||||
- Digikey API integration
|
- Digikey API integration
|
||||||
- Advanced routing algorithms
|
- Advanced routing algorithms
|
||||||
- Real-time UI synchronization via IPC API
|
|
||||||
- Smart BOM management
|
- Smart BOM management
|
||||||
|
|
||||||
**Roadmap:**
|
|
||||||
- AI-assisted component selection
|
- AI-assisted component selection
|
||||||
- Design pattern library (Arduino shields, RPi HATs)
|
- Design pattern library (Arduino shields, RPi HATs)
|
||||||
- Interactive design review mode
|
|
||||||
- Automated documentation generation
|
|
||||||
- Multi-board projects
|
|
||||||
|
|
||||||
See [ROADMAP.md](docs/ROADMAP.md) for detailed development timeline.
|
See [ROADMAP.md](docs/ROADMAP.md) for detailed development timeline.
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# KiCAD IPC Backend Implementation Status
|
# KiCAD IPC Backend Implementation Status
|
||||||
|
|
||||||
**Status:** 🟢 **FULLY INTEGRATED**
|
**Status:** Under Active Development and Testing
|
||||||
**Date:** 2025-11-30
|
**Date:** 2025-12-02
|
||||||
**KiCAD Version:** 9.0.6
|
**KiCAD Version:** 9.0.6
|
||||||
**kicad-python Version:** 0.5.0
|
**kicad-python Version:** 0.5.0
|
||||||
|
|
||||||
@@ -9,80 +9,94 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The IPC backend is now **fully integrated** as the **default backend** for all MCP tools. When KiCAD is running with IPC enabled, all commands automatically use real-time UI synchronization. Changes made through the MCP tools appear **instantly** in the KiCAD UI without requiring manual reload.
|
The IPC backend provides real-time UI synchronization with KiCAD 9.0+ via the official IPC API. When KiCAD is running with IPC enabled, commands can update the KiCAD UI immediately without requiring manual reload.
|
||||||
|
|
||||||
**SWIG backend is deprecated** and will be removed in a future version when KiCAD removes it (KiCAD 10.0).
|
This feature is experimental and under active testing. The server uses a hybrid approach: IPC when available, automatic fallback to SWIG when IPC is not connected.
|
||||||
|
|
||||||
## Key Benefits
|
## Key Differences
|
||||||
|
|
||||||
| Feature | SWIG (Old) | IPC (New) |
|
| Feature | SWIG | IPC |
|
||||||
|---------|------------|-----------|
|
|---------|------|-----|
|
||||||
| UI Updates | Manual reload required | **Instant** |
|
| UI Updates | Manual reload required | Immediate (when working) |
|
||||||
| Undo/Redo | Not supported | **Transaction support** |
|
| Undo/Redo | Not supported | Transaction support |
|
||||||
| API Stability | Deprecated, will break | **Stable, versioned** |
|
| API Stability | Deprecated in KiCAD 9 | Official, versioned |
|
||||||
| Connection | File-based | **Live socket connection** |
|
| Connection | File-based | Live socket connection |
|
||||||
| Future Support | Removed in KiCAD 10.0 | **Official & maintained** |
|
| KiCAD Required | No (file operations) | Yes (must be running) |
|
||||||
|
|
||||||
## Implemented Features
|
## Implemented IPC Commands
|
||||||
|
|
||||||
### Automatic IPC Routing
|
The following MCP commands have IPC handlers:
|
||||||
The following MCP commands **automatically use IPC** when available:
|
|
||||||
|
|
||||||
| Command | IPC Handler | Real-time |
|
| Command | IPC Handler | Status |
|
||||||
|---------|-------------|-----------|
|
|---------|-------------|--------|
|
||||||
| `route_trace` | `_ipc_route_trace` | Yes |
|
| `route_trace` | `_ipc_route_trace` | Implemented |
|
||||||
| `add_via` | `_ipc_add_via` | Yes |
|
| `add_via` | `_ipc_add_via` | Implemented |
|
||||||
| `add_net` | `_ipc_add_net` | Yes |
|
| `add_net` | `_ipc_add_net` | Implemented |
|
||||||
| `add_text` | `_ipc_add_text` | Yes |
|
| `delete_trace` | `_ipc_delete_trace` | Falls back to SWIG |
|
||||||
| `add_board_text` | `_ipc_add_text` | Yes |
|
| `get_nets_list` | `_ipc_get_nets_list` | Implemented |
|
||||||
| `set_board_size` | `_ipc_set_board_size` | Yes |
|
| `add_copper_pour` | `_ipc_add_copper_pour` | Implemented |
|
||||||
| `get_board_info` | `_ipc_get_board_info` | Yes |
|
| `refill_zones` | `_ipc_refill_zones` | Implemented |
|
||||||
| `place_component` | `_ipc_place_component` | Yes |
|
| `add_text` | `_ipc_add_text` | Implemented |
|
||||||
| `move_component` | `_ipc_move_component` | Yes |
|
| `add_board_text` | `_ipc_add_text` | Implemented |
|
||||||
| `delete_component` | `_ipc_delete_component` | Yes |
|
| `set_board_size` | `_ipc_set_board_size` | Implemented |
|
||||||
| `get_component_list` | `_ipc_get_component_list` | Yes |
|
| `get_board_info` | `_ipc_get_board_info` | Implemented |
|
||||||
| `save_project` | `_ipc_save_project` | Yes |
|
| `add_board_outline` | `_ipc_add_board_outline` | Implemented |
|
||||||
|
| `add_mounting_hole` | `_ipc_add_mounting_hole` | Implemented |
|
||||||
|
| `get_layer_list` | `_ipc_get_layer_list` | Implemented |
|
||||||
|
| `place_component` | `_ipc_place_component` | Implemented (hybrid) |
|
||||||
|
| `move_component` | `_ipc_move_component` | Implemented |
|
||||||
|
| `rotate_component` | `_ipc_rotate_component` | Implemented |
|
||||||
|
| `delete_component` | `_ipc_delete_component` | Implemented |
|
||||||
|
| `get_component_list` | `_ipc_get_component_list` | Implemented |
|
||||||
|
| `get_component_properties` | `_ipc_get_component_properties` | Implemented |
|
||||||
|
| `save_project` | `_ipc_save_project` | Implemented |
|
||||||
|
|
||||||
### Core Connection
|
### Implemented Backend Features
|
||||||
- [x] Connect to running KiCAD instance
|
|
||||||
- [x] Auto-detect socket path (`/tmp/kicad/api.sock`)
|
|
||||||
- [x] Version checking and validation
|
|
||||||
- [x] Ping/health check
|
|
||||||
- [x] Auto-fallback to SWIG when IPC unavailable
|
|
||||||
- [x] Change notification callbacks
|
|
||||||
|
|
||||||
### Board Operations
|
**Core Connection:**
|
||||||
- [x] Get board reference
|
- Connect to running KiCAD instance
|
||||||
- [x] Get/Set board size (via Edge.Cuts)
|
- Auto-detect socket path (`/tmp/kicad/api.sock`)
|
||||||
- [x] List enabled layers
|
- Version checking and validation
|
||||||
- [x] Save board
|
- Auto-fallback to SWIG when IPC unavailable
|
||||||
- [x] Get board bounding box
|
- Change notification callbacks
|
||||||
|
|
||||||
### Component Operations
|
**Board Operations:**
|
||||||
- [x] List all components
|
- Get board reference
|
||||||
- [x] Place component (real-time)
|
- Get/Set board size
|
||||||
- [x] Move component (real-time)
|
- List enabled layers
|
||||||
- [x] Delete component (real-time)
|
- Save board
|
||||||
- [x] Get component properties
|
- Add board outline segments
|
||||||
|
- Add mounting holes
|
||||||
|
|
||||||
### Routing Operations
|
**Component Operations:**
|
||||||
- [x] Add track (real-time)
|
- List all components
|
||||||
- [x] Add via (real-time)
|
- Place component (hybrid: SWIG for library loading, IPC for placement)
|
||||||
- [x] Get all tracks
|
- Move component
|
||||||
- [x] Get all vias
|
- Rotate component
|
||||||
- [x] Get all nets
|
- Delete component
|
||||||
|
- Get component properties
|
||||||
|
|
||||||
### UI Integration
|
**Routing Operations:**
|
||||||
- [x] Add text to board (real-time)
|
- Add track
|
||||||
- [x] Get current selection
|
- Add via
|
||||||
- [x] Clear selection
|
- Get all tracks
|
||||||
- [x] Refill zones
|
- Get all vias
|
||||||
|
- Get all nets
|
||||||
|
|
||||||
### Transaction Support
|
**Zone Operations:**
|
||||||
- [x] Begin transaction
|
- Add copper pour zones
|
||||||
- [x] Commit transaction (with description)
|
- Get zones list
|
||||||
- [x] Rollback transaction
|
- Refill zones
|
||||||
- [x] Proper undo/redo in KiCAD
|
|
||||||
|
**UI Integration:**
|
||||||
|
- Add text to board
|
||||||
|
- Get current selection
|
||||||
|
- Clear selection
|
||||||
|
|
||||||
|
**Transaction Support:**
|
||||||
|
- Begin transaction
|
||||||
|
- Commit transaction (with description for undo)
|
||||||
|
- Rollback transaction
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -98,46 +112,7 @@ The following MCP commands **automatically use IPC** when available:
|
|||||||
pip install kicad-python
|
pip install kicad-python
|
||||||
```
|
```
|
||||||
|
|
||||||
### Basic Usage
|
### Testing
|
||||||
|
|
||||||
```python
|
|
||||||
from kicad_api import create_backend
|
|
||||||
|
|
||||||
# Auto-detect and connect
|
|
||||||
backend = create_backend() # Will try IPC first, fall back to SWIG
|
|
||||||
backend.connect()
|
|
||||||
|
|
||||||
# Get board API
|
|
||||||
board = backend.get_board()
|
|
||||||
|
|
||||||
# Operations appear instantly in KiCAD UI!
|
|
||||||
board.add_track(
|
|
||||||
start_x=100.0, start_y=100.0,
|
|
||||||
end_x=120.0, end_y=100.0,
|
|
||||||
width=0.25, layer="F.Cu"
|
|
||||||
)
|
|
||||||
|
|
||||||
# With transaction support for undo
|
|
||||||
board.begin_transaction("Add components")
|
|
||||||
board.place_component("R1", "Resistor_SMD:R_0603", 50, 50)
|
|
||||||
board.place_component("C1", "Capacitor_SMD:C_0603", 60, 50)
|
|
||||||
board.commit_transaction("Added R1 and C1") # Single undo step
|
|
||||||
```
|
|
||||||
|
|
||||||
### Force Backend Selection
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Force IPC backend
|
|
||||||
backend = create_backend('ipc')
|
|
||||||
|
|
||||||
# Force SWIG backend (deprecated)
|
|
||||||
backend = create_backend('swig')
|
|
||||||
|
|
||||||
# Or via environment variable
|
|
||||||
# export KICAD_BACKEND=ipc
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
Run the test script to verify IPC functionality:
|
Run the test script to verify IPC functionality:
|
||||||
|
|
||||||
@@ -146,46 +121,43 @@ Run the test script to verify IPC functionality:
|
|||||||
./venv/bin/python python/test_ipc_backend.py
|
./venv/bin/python python/test_ipc_backend.py
|
||||||
```
|
```
|
||||||
|
|
||||||
The test script will:
|
|
||||||
1. Connect to KiCAD
|
|
||||||
2. List components on the board
|
|
||||||
3. Add a test track (visible instantly in UI)
|
|
||||||
4. Add a test via (visible instantly in UI)
|
|
||||||
5. Add test text (visible instantly in UI)
|
|
||||||
6. Read the current selection
|
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────┐
|
+-------------------------------------------------------------+
|
||||||
│ MCP Server (TypeScript/Node.js) │
|
| MCP Server (TypeScript/Node.js) |
|
||||||
└──────────────────────┬──────────────────────────────────────┘
|
+---------------------------+---------------------------------+
|
||||||
│ JSON commands
|
| JSON commands
|
||||||
┌──────────────────────▼──────────────────────────────────────┐
|
+---------------------------v---------------------------------+
|
||||||
│ Python Interface Layer │
|
| Python Interface Layer |
|
||||||
│ ┌────────────────────────────────────────────────────────┐ │
|
| +--------------------------------------------------------+ |
|
||||||
│ │ kicad_api/ipc_backend.py │ │
|
| | kicad_interface.py | |
|
||||||
│ │ - IPCBackend (connection management) │ │
|
| | - Routes commands to IPC or SWIG handlers | |
|
||||||
│ │ - IPCBoardAPI (board operations) │ │
|
| | - IPC_CAPABLE_COMMANDS dict defines routing | |
|
||||||
│ └────────────────────────────────────────────────────────┘ │
|
| +--------------------------------------------------------+ |
|
||||||
└──────────────────────┬──────────────────────────────────────┘
|
| +--------------------------------------------------------+ |
|
||||||
│ kicad-python (kipy) library
|
| | kicad_api/ipc_backend.py | |
|
||||||
┌──────────────────────▼──────────────────────────────────────┐
|
| | - IPCBackend (connection management) | |
|
||||||
│ Protocol Buffers over UNIX Sockets │
|
| | - IPCBoardAPI (board operations) | |
|
||||||
└──────────────────────┬──────────────────────────────────────┘
|
| +--------------------------------------------------------+ |
|
||||||
│
|
+---------------------------+---------------------------------+
|
||||||
┌──────────────────────▼──────────────────────────────────────┐
|
| kicad-python (kipy) library
|
||||||
│ KiCAD 9.0+ (IPC Server) │
|
+---------------------------v---------------------------------+
|
||||||
│ Changes appear instantly in UI! │
|
| Protocol Buffers over UNIX Sockets |
|
||||||
└─────────────────────────────────────────────────────────────┘
|
+---------------------------+---------------------------------+
|
||||||
|
|
|
||||||
|
+---------------------------v---------------------------------+
|
||||||
|
| KiCAD 9.0+ (IPC Server) |
|
||||||
|
+-------------------------------------------------------------+
|
||||||
```
|
```
|
||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
|
|
||||||
1. **KiCAD must be running**: Unlike SWIG, IPC requires KiCAD to be open
|
1. **KiCAD must be running**: Unlike SWIG, IPC requires KiCAD to be open
|
||||||
2. **Project creation**: Must be done through KiCAD UI or file system
|
2. **Project creation**: Not supported via IPC, uses file system
|
||||||
3. **Footprint library access**: Limited - best to use library management separately
|
3. **Footprint library access**: Uses hybrid approach (SWIG loads from library, IPC places)
|
||||||
4. **Layer management**: Layers are predefined in KiCAD
|
4. **Delete trace**: Falls back to SWIG (IPC API doesn't support direct deletion)
|
||||||
|
5. **Some operations may not work as expected**: This is experimental code
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -213,19 +185,20 @@ python/kicad_api/
|
|||||||
├── __init__.py # Package exports
|
├── __init__.py # Package exports
|
||||||
├── base.py # Abstract base classes
|
├── base.py # Abstract base classes
|
||||||
├── factory.py # Backend auto-detection
|
├── factory.py # Backend auto-detection
|
||||||
├── ipc_backend.py # IPC implementation (NEW)
|
├── ipc_backend.py # IPC implementation
|
||||||
└── swig_backend.py # Legacy SWIG wrapper
|
└── swig_backend.py # Legacy SWIG wrapper
|
||||||
|
|
||||||
python/
|
python/
|
||||||
└── test_ipc_backend.py # IPC test script
|
└── test_ipc_backend.py # IPC test script
|
||||||
```
|
```
|
||||||
|
|
||||||
## Future Enhancements
|
## Future Work
|
||||||
|
|
||||||
1. **Footprint library integration via IPC** - Load footprints directly
|
1. More comprehensive testing of all IPC commands
|
||||||
2. **Schematic IPC support** - When available in kicad-python
|
2. Footprint library integration via IPC (when kipy supports it)
|
||||||
3. **Event subscriptions** - React to changes made in KiCAD UI
|
3. Schematic IPC support (when available in kicad-python)
|
||||||
4. **Multi-board support** - Handle multiple open boards
|
4. Event subscriptions to react to changes made in KiCAD UI
|
||||||
|
5. Multi-board support
|
||||||
|
|
||||||
## Related Documentation
|
## Related Documentation
|
||||||
|
|
||||||
@@ -236,5 +209,4 @@ python/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated:** 2025-11-30
|
**Last Updated:** 2025-12-02
|
||||||
**Maintained by:** KiCAD MCP Team
|
|
||||||
|
|||||||
@@ -1,60 +1,17 @@
|
|||||||
# Known Issues & Workarounds
|
# Known Issues & Workarounds
|
||||||
|
|
||||||
**Last Updated:** 2025-10-26
|
**Last Updated:** 2025-12-02
|
||||||
**Version:** 2.0.0-alpha.2
|
**Version:** 2.1.0-alpha
|
||||||
|
|
||||||
This document tracks known issues and provides workarounds where available.
|
This document tracks known issues and provides workarounds where available.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🐛 Current Issues
|
## Current Issues
|
||||||
|
|
||||||
### 1. Component Placement Fails - Library Path Not Found
|
### 1. `get_board_info` KiCAD 9.0 API Issue
|
||||||
|
|
||||||
**Status:** 🔴 **BLOCKING** - Cannot place components
|
**Status:** KNOWN - Non-critical
|
||||||
|
|
||||||
**Symptoms:**
|
|
||||||
```
|
|
||||||
Error: Could not find footprint library
|
|
||||||
```
|
|
||||||
|
|
||||||
**Root Cause:** MCP server doesn't have access to KiCAD's footprint library paths
|
|
||||||
|
|
||||||
**Workaround:** None currently - feature not usable
|
|
||||||
|
|
||||||
**Fix Plan:** Week 2 priority
|
|
||||||
- Detect KiCAD library paths from environment
|
|
||||||
- Add configuration for custom library paths
|
|
||||||
- Integrate JLCPCB/Digikey part databases
|
|
||||||
|
|
||||||
**Tracking:** High Priority - Required for any real PCB design
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Routing Operations Untested with KiCAD 9.0
|
|
||||||
|
|
||||||
**Status:** 🟡 **UNKNOWN** - May have API compatibility issues
|
|
||||||
|
|
||||||
**Affected Commands:**
|
|
||||||
- `route_trace`
|
|
||||||
- `add_via`
|
|
||||||
- `add_copper_pour`
|
|
||||||
- `route_differential_pair`
|
|
||||||
|
|
||||||
**Symptoms:** May fail with API type mismatch errors (like set_board_size did)
|
|
||||||
|
|
||||||
**Workaround:** None - needs testing and fixes
|
|
||||||
|
|
||||||
**Fix Plan:** Week 2 priority
|
|
||||||
- Test each routing command with KiCAD 9.0
|
|
||||||
- Fix API compatibility issues
|
|
||||||
- Add comprehensive routing examples
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. `get_board_info` KiCAD 9.0 API Issue
|
|
||||||
|
|
||||||
**Status:** 🟡 **KNOWN** - Non-critical
|
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
```
|
```
|
||||||
@@ -65,26 +22,37 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
|||||||
|
|
||||||
**Workaround:** Use `get_project_info` instead for basic project details
|
**Workaround:** Use `get_project_info` instead for basic project details
|
||||||
|
|
||||||
**Fix Plan:** Week 2
|
|
||||||
- Update to use KiCAD 9.0 layer constants
|
|
||||||
- Add backward compatibility for KiCAD 8.x
|
|
||||||
|
|
||||||
**Impact:** Low - informational command only
|
**Impact:** Low - informational command only
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 4. UI Auto-Reload Requires Manual Confirmation
|
### 2. Zone Filling via SWIG Causes Segfault
|
||||||
|
|
||||||
**Status:** 🟢 **BY DESIGN** - Will be fixed by IPC
|
**Status:** KNOWN - Workaround available
|
||||||
|
|
||||||
**Symptoms:**
|
**Symptoms:**
|
||||||
- MCP makes changes
|
- Copper pours created but not filled automatically when using SWIG backend
|
||||||
- KiCAD detects file change
|
- Calling `ZONE_FILLER` via SWIG causes segfault
|
||||||
- User must click "Reload" button to see changes
|
|
||||||
|
**Workaround Options:**
|
||||||
|
1. Use IPC backend (zones fill correctly via IPC)
|
||||||
|
2. Open the board in KiCAD UI - zones fill automatically when opened
|
||||||
|
|
||||||
|
**Impact:** Medium - affects copper pour visualization until opened in KiCAD
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. UI Manual Reload Required (SWIG Backend)
|
||||||
|
|
||||||
|
**Status:** BY DESIGN - Fixed by IPC
|
||||||
|
|
||||||
|
**Symptoms:**
|
||||||
|
- MCP makes changes via SWIG backend
|
||||||
|
- KiCAD doesn't show changes until file is reloaded
|
||||||
|
|
||||||
**Current Workflow:**
|
**Current Workflow:**
|
||||||
```
|
```
|
||||||
1. Claude makes change via MCP
|
1. MCP makes change via SWIG
|
||||||
2. KiCAD shows: "File has been modified. Reload? [Yes] [No]"
|
2. KiCAD shows: "File has been modified. Reload? [Yes] [No]"
|
||||||
3. User clicks "Yes"
|
3. User clicks "Yes"
|
||||||
4. Changes appear in UI
|
4. Changes appear in UI
|
||||||
@@ -92,45 +60,88 @@ AttributeError: 'BOARD' object has no attribute 'LT_USER'
|
|||||||
|
|
||||||
**Why:** SWIG-based backend requires file I/O, can't push changes to running UI
|
**Why:** SWIG-based backend requires file I/O, can't push changes to running UI
|
||||||
|
|
||||||
**Fix Plan:** Weeks 2-3 - IPC Backend Migration
|
**Fix:** Use IPC backend for real-time updates (requires KiCAD to be running with IPC enabled)
|
||||||
- Connect to KiCAD via IPC socket
|
|
||||||
- Make changes directly in running instance
|
|
||||||
- No file reload needed - instant visual feedback
|
|
||||||
|
|
||||||
**Workaround:** This is the current expected behavior - just click reload!
|
**Workaround:** Click reload prompt or use File > Revert
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔧 Recently Fixed
|
### 4. IPC Backend Experimental
|
||||||
|
|
||||||
### ✅ KiCAD Process Detection (Fixed 2025-10-26)
|
**Status:** UNDER DEVELOPMENT
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
The IPC backend is currently being implemented and tested. Some commands may not work as expected in all scenarios.
|
||||||
|
|
||||||
|
**Known IPC Limitations:**
|
||||||
|
- KiCAD must be running with IPC enabled
|
||||||
|
- Some commands fall back to SWIG (e.g., delete_trace)
|
||||||
|
- Footprint loading uses hybrid approach (SWIG for library, IPC for placement)
|
||||||
|
- Error handling may not be comprehensive in all cases
|
||||||
|
|
||||||
|
**Workaround:** If IPC fails, the server automatically falls back to SWIG backend
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Schematic Support Limited
|
||||||
|
|
||||||
|
**Status:** KNOWN - Partial support
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
Schematic operations use the kicad-skip library which has some limitations with KiCAD 9.0 file format changes.
|
||||||
|
|
||||||
|
**Affected Commands:**
|
||||||
|
- `create_schematic`
|
||||||
|
- `add_schematic_component`
|
||||||
|
- `add_schematic_wire`
|
||||||
|
|
||||||
|
**Workaround:** Manual schematic creation may be more reliable for complex designs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recently Fixed
|
||||||
|
|
||||||
|
### Component Library Integration (Fixed 2025-11-01)
|
||||||
|
|
||||||
|
**Was:** Could not find footprint libraries
|
||||||
|
**Now:** Auto-discovers 153 KiCAD footprint libraries, search and list working
|
||||||
|
|
||||||
|
### Routing Operations KiCAD 9.0 (Fixed 2025-11-01)
|
||||||
|
|
||||||
|
**Was:** Multiple API compatibility issues with KiCAD 9.0
|
||||||
|
**Now:** All routing commands tested and working:
|
||||||
|
- `netinfo.FindNet()` -> `netinfo.NetsByName()[name]`
|
||||||
|
- `zone.SetPriority()` -> `zone.SetAssignedPriority()`
|
||||||
|
- `ZONE_FILL_MODE_POLYGON` -> `ZONE_FILL_MODE_POLYGONS`
|
||||||
|
|
||||||
|
### KiCAD Process Detection (Fixed 2025-10-26)
|
||||||
|
|
||||||
**Was:** `check_kicad_ui` detected MCP server's own processes
|
**Was:** `check_kicad_ui` detected MCP server's own processes
|
||||||
**Now:** Properly filters to only detect actual KiCAD binaries
|
**Now:** Properly filters to only detect actual KiCAD binaries
|
||||||
|
|
||||||
### ✅ set_board_size KiCAD 9.0 (Fixed 2025-10-26)
|
### set_board_size KiCAD 9.0 (Fixed 2025-10-26)
|
||||||
|
|
||||||
**Was:** Failed with `BOX2I_SetSize` type error
|
**Was:** Failed with `BOX2I_SetSize` type error
|
||||||
**Now:** Works with KiCAD 9.0 API, backward compatible with 8.x
|
**Now:** Works with KiCAD 9.0 API
|
||||||
|
|
||||||
### ✅ add_board_text KiCAD 9.0 (Fixed 2025-10-26)
|
### add_board_text KiCAD 9.0 (Fixed 2025-10-26)
|
||||||
|
|
||||||
**Was:** Failed with `EDA_ANGLE` type error
|
**Was:** Failed with `EDA_ANGLE` type error
|
||||||
**Now:** Works with KiCAD 9.0 API, backward compatible with 8.x
|
**Now:** Works with KiCAD 9.0 API
|
||||||
|
|
||||||
### ✅ Missing add_board_text Command (Fixed 2025-10-26)
|
### Schematic Parameter Mismatch (Fixed 2025-12-02)
|
||||||
|
|
||||||
**Was:** Command not found error
|
**Was:** `create_schematic` failed due to parameter name differences between TypeScript and Python
|
||||||
**Now:** Properly mapped to Python handler
|
**Now:** Accepts multiple parameter naming conventions (`name`, `projectName`, `title`, `filename`)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 Reporting New Issues
|
## Reporting New Issues
|
||||||
|
|
||||||
If you encounter an issue not listed here:
|
If you encounter an issue not listed here:
|
||||||
|
|
||||||
1. **Check MCP logs:** `~/.kicad-mcp/logs/kicad_interface.log`
|
1. **Check MCP logs:** `~/.kicad-mcp/logs/kicad_interface.log`
|
||||||
2. **Check KiCAD version:** `pcbnew --version` (must be 9.0+)
|
2. **Check KiCAD version:** `python3 -c "import pcbnew; print(pcbnew.GetBuildVersion())"` (must be 9.0+)
|
||||||
3. **Try the operation in KiCAD directly** - is it a KiCAD issue?
|
3. **Try the operation in KiCAD directly** - is it a KiCAD issue?
|
||||||
4. **Open GitHub issue** with:
|
4. **Open GitHub issue** with:
|
||||||
- Error message
|
- Error message
|
||||||
@@ -141,18 +152,18 @@ If you encounter an issue not listed here:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Priority Matrix
|
## Priority Matrix
|
||||||
|
|
||||||
| Issue | Priority | Impact | Effort | Status |
|
| Issue | Priority | Impact | Status |
|
||||||
|-------|----------|--------|--------|--------|
|
|-------|----------|--------|--------|
|
||||||
| Component Library Integration | 🔴 Critical | High | Medium | Week 2 |
|
| IPC Backend Testing | High | Medium | In Progress |
|
||||||
| Routing KiCAD 9.0 Compatibility | 🟡 High | High | Low | Week 2 |
|
| get_board_info Fix | Low | Low | Known |
|
||||||
| IPC Backend (Real-time UI) | 🟡 High | Medium | High | Week 2-3 |
|
| Zone Filling (SWIG) | Medium | Medium | Workaround Available |
|
||||||
| get_board_info Fix | 🟢 Low | Low | Low | Week 2 |
|
| Schematic Support | Medium | Medium | Partial |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 💡 General Workarounds
|
## General Workarounds
|
||||||
|
|
||||||
### Server Won't Start
|
### Server Won't Start
|
||||||
```bash
|
```bash
|
||||||
@@ -169,15 +180,25 @@ python3 python/utils/platform_helper.py
|
|||||||
# Always run open_project after server restart
|
# Always run open_project after server restart
|
||||||
```
|
```
|
||||||
|
|
||||||
### KiCAD UI Doesn't Show Changes
|
### KiCAD UI Doesn't Show Changes (SWIG Mode)
|
||||||
```
|
```
|
||||||
# File → Revert (or click reload prompt)
|
# File > Revert (or click reload prompt)
|
||||||
# Or: Close and reopen file in KiCAD
|
# Or: Close and reopen file in KiCAD
|
||||||
|
# Or: Use IPC backend for automatic updates
|
||||||
|
```
|
||||||
|
|
||||||
|
### IPC Not Connecting
|
||||||
|
```
|
||||||
|
# Ensure KiCAD is running
|
||||||
|
# Enable IPC: Preferences > Plugins > Enable IPC API Server
|
||||||
|
# Have a board open in PCB editor
|
||||||
|
# Check socket exists: ls /tmp/kicad/api.sock
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Need Help?**
|
**Need Help?**
|
||||||
- Check [docs/VISUAL_FEEDBACK.md](VISUAL_FEEDBACK.md) for workflow tips
|
- Check [IPC_BACKEND_STATUS.md](IPC_BACKEND_STATUS.md) for IPC details
|
||||||
- Check [docs/UI_AUTO_LAUNCH.md](UI_AUTO_LAUNCH.md) for UI setup
|
- Check [REALTIME_WORKFLOW.md](REALTIME_WORKFLOW.md) for workflow tips
|
||||||
|
- Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
||||||
- Open an issue on GitHub
|
- Open an issue on GitHub
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# KiCAD MCP - Current Status Summary
|
# KiCAD MCP - Current Status Summary
|
||||||
|
|
||||||
**Date:** 2025-11-01
|
**Date:** 2025-12-02
|
||||||
**Version:** 2.1.0-alpha
|
**Version:** 2.1.0-alpha
|
||||||
**Phase:** Week 2 Nearly Complete - Production Features Ready
|
**Phase:** IPC Backend Implementation and Testing
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,17 +11,17 @@
|
|||||||
| Metric | Value | Status |
|
| Metric | Value | Status |
|
||||||
|--------|-------|--------|
|
|--------|-------|--------|
|
||||||
| Core Features Working | 18/20 | 90% |
|
| Core Features Working | 18/20 | 90% |
|
||||||
| KiCAD 9.0 Compatible | Yes | Yes |
|
| KiCAD 9.0 Compatible | Yes | Verified |
|
||||||
| UI Auto-launch | Working | Yes |
|
| UI Auto-launch | Working | Verified |
|
||||||
| Component Placement | Working | Yes |
|
| Component Placement | Working | Verified |
|
||||||
| Component Libraries | 153 libraries | Yes |
|
| Component Libraries | 153 libraries | Verified |
|
||||||
| Routing Operations | Working | Yes |
|
| Routing Operations | Working | Verified |
|
||||||
| Real-time Collaboration | Working | Yes |
|
| IPC Backend | Under Testing | Experimental |
|
||||||
| Tests Passing | 18/20 | 90% |
|
| Tests Passing | 18/20 | 90% |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What's Working (Verified 2025-11-01)
|
## What's Working (Verified 2025-12-02)
|
||||||
|
|
||||||
### Project Management
|
### Project Management
|
||||||
- `create_project` - Create new KiCAD projects
|
- `create_project` - Create new KiCAD projects
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
- `set_active_layer` - Layer switching
|
- `set_active_layer` - Layer switching
|
||||||
- `get_layer_list` - List all layers
|
- `get_layer_list` - List all layers
|
||||||
|
|
||||||
### Component Operations (NEW - WORKING)
|
### Component Operations
|
||||||
- `place_component` - Place components with library footprints (KiCAD 9.0 fixed)
|
- `place_component` - Place components with library footprints (KiCAD 9.0 fixed)
|
||||||
- `move_component` - Move components
|
- `move_component` - Move components
|
||||||
- `rotate_component` - Rotate components (EDA_ANGLE fixed)
|
- `rotate_component` - Rotate components (EDA_ANGLE fixed)
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
- `GetOrientation()` returns `EDA_ANGLE`, call `.AsDegrees()`
|
- `GetOrientation()` returns `EDA_ANGLE`, call `.AsDegrees()`
|
||||||
- `GetFootprintName()` now `GetFPIDAsString()`
|
- `GetFootprintName()` now `GetFPIDAsString()`
|
||||||
|
|
||||||
### Routing Operations (NEW - WORKING)
|
### Routing Operations
|
||||||
- `add_net` - Create electrical nets
|
- `add_net` - Create electrical nets
|
||||||
- `route_trace` - Add copper traces (KiCAD 9.0 fixed)
|
- `route_trace` - Add copper traces (KiCAD 9.0 fixed)
|
||||||
- `add_via` - Add vias between layers (KiCAD 9.0 fixed)
|
- `add_via` - Add vias between layers (KiCAD 9.0 fixed)
|
||||||
@@ -69,18 +69,10 @@
|
|||||||
- `zone.SetPriority()` now `zone.SetAssignedPriority()`
|
- `zone.SetPriority()` now `zone.SetAssignedPriority()`
|
||||||
- `ZONE_FILL_MODE_POLYGON` now `ZONE_FILL_MODE_POLYGONS`
|
- `ZONE_FILL_MODE_POLYGON` now `ZONE_FILL_MODE_POLYGONS`
|
||||||
- Zone outline requires `outline.NewOutline()` first
|
- Zone outline requires `outline.NewOutline()` first
|
||||||
- Zone filling disabled (SWIG API segfault) - zones filled when opened in UI
|
|
||||||
|
|
||||||
### Real-time Collaboration (NEW - TESTED)
|
|
||||||
- **MCP to UI Workflow:** AI places components, Human reloads in KiCAD UI, Components visible
|
|
||||||
- **UI to MCP Workflow:** Human edits in UI, Save, AI reads changes
|
|
||||||
- Latency: ~1-5 seconds (manual save/reload)
|
|
||||||
- Full documentation: [REALTIME_WORKFLOW.md](./REALTIME_WORKFLOW.md)
|
|
||||||
|
|
||||||
### UI Management
|
### UI Management
|
||||||
- `check_kicad_ui` - Detect running KiCAD
|
- `check_kicad_ui` - Detect running KiCAD
|
||||||
- `launch_kicad_ui` - Auto-launch with project
|
- `launch_kicad_ui` - Auto-launch with project
|
||||||
- Visual feedback workflow (manual reload)
|
|
||||||
|
|
||||||
### Export
|
### Export
|
||||||
- `export_gerber` - Manufacturing files
|
- `export_gerber` - Manufacturing files
|
||||||
@@ -96,6 +88,59 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## IPC Backend (Under Development)
|
||||||
|
|
||||||
|
We are currently implementing and testing the KiCAD 9.0 IPC API for real-time UI synchronization. This is experimental and may not work perfectly in all scenarios.
|
||||||
|
|
||||||
|
### IPC-Capable Commands (21 total)
|
||||||
|
|
||||||
|
The following commands have IPC handlers implemented:
|
||||||
|
|
||||||
|
| Command | IPC Handler | Notes |
|
||||||
|
|---------|-------------|-------|
|
||||||
|
| `route_trace` | `_ipc_route_trace` | Implemented |
|
||||||
|
| `add_via` | `_ipc_add_via` | Implemented |
|
||||||
|
| `add_net` | `_ipc_add_net` | Implemented |
|
||||||
|
| `delete_trace` | `_ipc_delete_trace` | Falls back to SWIG |
|
||||||
|
| `get_nets_list` | `_ipc_get_nets_list` | Implemented |
|
||||||
|
| `add_copper_pour` | `_ipc_add_copper_pour` | Implemented |
|
||||||
|
| `refill_zones` | `_ipc_refill_zones` | Implemented |
|
||||||
|
| `add_text` | `_ipc_add_text` | Implemented |
|
||||||
|
| `add_board_text` | `_ipc_add_text` | Implemented |
|
||||||
|
| `set_board_size` | `_ipc_set_board_size` | Implemented |
|
||||||
|
| `get_board_info` | `_ipc_get_board_info` | Implemented |
|
||||||
|
| `add_board_outline` | `_ipc_add_board_outline` | Implemented |
|
||||||
|
| `add_mounting_hole` | `_ipc_add_mounting_hole` | Implemented |
|
||||||
|
| `get_layer_list` | `_ipc_get_layer_list` | Implemented |
|
||||||
|
| `place_component` | `_ipc_place_component` | Hybrid (SWIG+IPC) |
|
||||||
|
| `move_component` | `_ipc_move_component` | Implemented |
|
||||||
|
| `rotate_component` | `_ipc_rotate_component` | Implemented |
|
||||||
|
| `delete_component` | `_ipc_delete_component` | Implemented |
|
||||||
|
| `get_component_list` | `_ipc_get_component_list` | Implemented |
|
||||||
|
| `get_component_properties` | `_ipc_get_component_properties` | Implemented |
|
||||||
|
| `save_project` | `_ipc_save_project` | Implemented |
|
||||||
|
|
||||||
|
### How IPC Works
|
||||||
|
|
||||||
|
When KiCAD is running with IPC enabled:
|
||||||
|
1. Commands check if IPC is connected
|
||||||
|
2. If connected, use IPC handler for real-time UI updates
|
||||||
|
3. If not connected, fall back to SWIG API
|
||||||
|
|
||||||
|
**To enable IPC:**
|
||||||
|
1. KiCAD 9.0+ must be running
|
||||||
|
2. Enable IPC API: `Preferences > Plugins > Enable IPC API Server`
|
||||||
|
3. Have a board open in the PCB editor
|
||||||
|
|
||||||
|
### Known Limitations
|
||||||
|
|
||||||
|
- KiCAD must be running for IPC to work
|
||||||
|
- Some commands may not work as expected (still testing)
|
||||||
|
- Footprint loading uses hybrid approach (SWIG for library, IPC for placement)
|
||||||
|
- Delete trace falls back to SWIG (IPC API limitation)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## What Needs Work
|
## What Needs Work
|
||||||
|
|
||||||
### Minor Issues (NON-BLOCKING)
|
### Minor Issues (NON-BLOCKING)
|
||||||
@@ -104,67 +149,37 @@
|
|||||||
- Error: `AttributeError: 'BOARD' object has no attribute 'LT_USER'`
|
- Error: `AttributeError: 'BOARD' object has no attribute 'LT_USER'`
|
||||||
- Impact: Low (informational command only)
|
- Impact: Low (informational command only)
|
||||||
- Workaround: Use `get_project_info` or read components directly
|
- Workaround: Use `get_project_info` or read components directly
|
||||||
- Fix: Update layer constants for KiCAD 9.0 (30 min task)
|
|
||||||
|
|
||||||
**2. Zone filling**
|
**2. Zone filling via SWIG**
|
||||||
- Copper pours created but not filled automatically
|
- Copper pours created but not filled automatically via SWIG
|
||||||
- Cause: SWIG API segfault when calling `ZONE_FILLER`
|
- Cause: SWIG API segfault when calling `ZONE_FILLER`
|
||||||
- Workaround: Zones are filled automatically when opened in KiCAD UI
|
- Workaround: Use IPC backend or zones are filled when opened in KiCAD UI
|
||||||
- Fix: Will be resolved with IPC backend (Week 3)
|
|
||||||
|
|
||||||
**3. UI manual reload**
|
**3. UI manual reload (SWIG mode)**
|
||||||
- User must manually reload to see MCP changes
|
- User must manually reload to see MCP changes when using SWIG
|
||||||
- Impact: Workflow friction (~2 seconds)
|
- Impact: Workflow friction
|
||||||
- Workaround: File → Revert or close/reopen PCB editor
|
- Workaround: Use IPC backend for automatic updates
|
||||||
- Fix: IPC backend will enable automatic refresh (Week 3)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Current Progress
|
|
||||||
|
|
||||||
### Week 2 Goals (NEARLY COMPLETE)
|
|
||||||
|
|
||||||
**Must Have:**
|
|
||||||
1. **Component library integration** → 153 libraries auto-discovered, search working
|
|
||||||
2. **Routing operations** → All operations tested and working with KiCAD 9.0
|
|
||||||
3. **JLCPCB integration** → Planned and designed, ready to implement
|
|
||||||
|
|
||||||
**Should Have:**
|
|
||||||
4. Fix `get_board_info` API issue (deferred, low priority)
|
|
||||||
5. Create example project (LED blinker)
|
|
||||||
6. Real-time collaboration documented
|
|
||||||
|
|
||||||
**Bonus Achievements:**
|
|
||||||
- Real-time collaboration workflow tested end-to-end
|
|
||||||
- Comprehensive documentation (3 new docs created)
|
|
||||||
- All KiCAD 9.0 API compatibility issues resolved
|
|
||||||
|
|
||||||
### Overall v2.0 Progress
|
|
||||||
```
|
|
||||||
Week 1: ████████████████████ 100% Linux support + IPC prep
|
|
||||||
Week 2: ████████████████░░░░ 80% Libraries + Routing + Real-time
|
|
||||||
Week 3: ░░░░░░░░░░░░░░░░░░░░ 0% IPC Backend (next)
|
|
||||||
...
|
|
||||||
Overall: ████████░░░░░░░░░░░░ 40%
|
|
||||||
```
|
|
||||||
|
|
||||||
**Production Readiness:** 75% - Can design and manufacture PCBs, needs IPC for optimal UX
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Architecture Status
|
## Architecture Status
|
||||||
|
|
||||||
### SWIG Backend (Current) **PRODUCTION READY**
|
### SWIG Backend (File-based)
|
||||||
- **Status:** Stable and fully functional
|
- **Status:** Stable and functional
|
||||||
- **Pros:** No KiCAD process required, works offline, reliable
|
- **Pros:** No KiCAD process required, works offline, reliable
|
||||||
- **Cons:** Requires manual file reload for UI updates, no zone filling
|
- **Cons:** Requires manual file reload for UI updates, no zone filling
|
||||||
- **Future:** Will be maintained alongside IPC as fallback/offline mode
|
- **Use Case:** Offline work, automated pipelines, batch operations
|
||||||
|
|
||||||
### IPC Backend (Week 3) **NEXT PRIORITY**
|
### IPC Backend (Real-time)
|
||||||
- **Status:** Planned, not yet implemented
|
- **Status:** Under active development and testing
|
||||||
- **Pros:** Real-time UI updates (<100ms), no file I/O, zone filling works
|
- **Pros:** Real-time UI updates, no file I/O for many operations, zone filling works
|
||||||
- **Cons:** Requires KiCAD running, more complex
|
- **Cons:** Requires KiCAD running, experimental
|
||||||
- **Future:** Primary backend for interactive use
|
- **Use Case:** Interactive design sessions, paired programming with AI
|
||||||
|
|
||||||
|
### Hybrid Approach
|
||||||
|
The server automatically selects the best backend:
|
||||||
|
- IPC when KiCAD is running with IPC enabled
|
||||||
|
- SWIG fallback when IPC is unavailable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -175,40 +190,38 @@ Overall: ████████░░░░░░░░░░░░ 40%
|
|||||||
| Project Management | 100% | Create, open, save, info |
|
| Project Management | 100% | Create, open, save, info |
|
||||||
| Board Setup | 100% | Size, outline, mounting holes |
|
| Board Setup | 100% | Size, outline, mounting holes |
|
||||||
| Component Placement | 100% | Place, move, rotate, delete + 153 libraries |
|
| Component Placement | 100% | Place, move, rotate, delete + 153 libraries |
|
||||||
| Routing | 90% | Traces, vias, copper (no auto-fill) |
|
| Routing | 90% | Traces, vias, copper (zone filling via IPC) |
|
||||||
| Design Rules | 100% | Set, get, run DRC |
|
| Design Rules | 100% | Set, get, run DRC |
|
||||||
| Export | 100% | Gerber, PDF, SVG, 3D, BOM |
|
| Export | 100% | Gerber, PDF, SVG, 3D, BOM |
|
||||||
| UI Integration | 85% | Launch, check, manual reload |
|
| UI Integration | 85% | Launch, check, IPC auto-updates |
|
||||||
| Real-time Collab | 85% | MCP↔UI sync (manual save/reload) |
|
| IPC Backend | 60% | Under testing, 21 commands implemented |
|
||||||
| JLCPCB Integration | 0% | Planned, not implemented |
|
| JLCPCB Integration | 0% | Planned |
|
||||||
| IPC Backend | 0% | Planned for Week 3 |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Developer Setup Status
|
## Developer Setup Status
|
||||||
|
|
||||||
### Linux **EXCELLENT**
|
### Linux - Primary Platform
|
||||||
- KiCAD 9.0 detection:
|
- KiCAD 9.0 detection: Working
|
||||||
- Process management:
|
- Process management: Working
|
||||||
- venv support:
|
- venv support: Working
|
||||||
- Library discovery: (153 libraries)
|
- Library discovery: Working (153 libraries)
|
||||||
- Testing:
|
- Testing: Working
|
||||||
- Real-time workflow:
|
- IPC backend: Under testing
|
||||||
|
|
||||||
### Windows **SUPPORTED**
|
### Windows - Supported
|
||||||
- Automated setup script (`setup-windows.ps1`)
|
- Automated setup script (`setup-windows.ps1`)
|
||||||
- Process detection implemented
|
- Process detection implemented
|
||||||
- Library paths auto-detected
|
- Library paths auto-detected
|
||||||
- Comprehensive error diagnostics
|
- Comprehensive error diagnostics
|
||||||
- Startup validation with helpful errors
|
- Startup validation with helpful errors
|
||||||
- Troubleshooting guide (WINDOWS_TROUBLESHOOTING.md)
|
- Troubleshooting guide (WINDOWS_TROUBLESHOOTING.md)
|
||||||
- Community tested (needs more testing)
|
|
||||||
|
|
||||||
### macOS **UNTESTED**
|
### macOS - Untested
|
||||||
- Configuration provided
|
- Configuration provided
|
||||||
- Process detection implemented
|
- Process detection implemented
|
||||||
- Library paths configured
|
- Library paths configured
|
||||||
- Needs testing
|
- Needs community testing
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -216,129 +229,59 @@ Overall: ████████░░░░░░░░░░░░ 40%
|
|||||||
|
|
||||||
### Complete
|
### Complete
|
||||||
- [x] README.md
|
- [x] README.md
|
||||||
- [x] CHANGELOG_2025-10-26.md
|
- [x] ROADMAP.md
|
||||||
|
- [x] IPC_BACKEND_STATUS.md
|
||||||
|
- [x] IPC_API_MIGRATION_PLAN.md
|
||||||
|
- [x] REALTIME_WORKFLOW.md
|
||||||
|
- [x] LIBRARY_INTEGRATION.md
|
||||||
|
- [x] KNOWN_ISSUES.md
|
||||||
- [x] UI_AUTO_LAUNCH.md
|
- [x] UI_AUTO_LAUNCH.md
|
||||||
- [x] VISUAL_FEEDBACK.md
|
- [x] VISUAL_FEEDBACK.md
|
||||||
- [x] CLIENT_CONFIGURATION.md
|
- [x] CLIENT_CONFIGURATION.md
|
||||||
- [x] BUILD_AND_TEST_SESSION.md
|
- [x] BUILD_AND_TEST_SESSION.md
|
||||||
- [x] KNOWN_ISSUES.md
|
|
||||||
- [x] ROADMAP.md
|
|
||||||
- [x] STATUS_SUMMARY.md (this document)
|
- [x] STATUS_SUMMARY.md (this document)
|
||||||
- [x] **LIBRARY_INTEGRATION.md** (new 2025-11-01) ✨
|
- [x] WINDOWS_SETUP.md
|
||||||
- [x] **REALTIME_WORKFLOW.md** (new 2025-11-01) ✨
|
- [x] WINDOWS_TROUBLESHOOTING.md
|
||||||
- [x] **JLCPCB_INTEGRATION_PLAN.md** (new 2025-11-01) ✨
|
|
||||||
|
|
||||||
### Needed
|
### Needed
|
||||||
- [ ] EXAMPLE_PROJECTS.md (LED blinker, Arduino shield)
|
- [ ] EXAMPLE_PROJECTS.md
|
||||||
- [ ] VIDEO_TUTORIALS.md (when created)
|
|
||||||
- [ ] CONTRIBUTING.md
|
- [ ] CONTRIBUTING.md
|
||||||
- [ ] API_REFERENCE.md (comprehensive tool docs)
|
- [ ] API_REFERENCE.md
|
||||||
- [ ] IPC_BACKEND.md (Week 3)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recent Achievements (2025-11-01)
|
|
||||||
|
|
||||||
**Week 2 Major Milestones:**
|
|
||||||
|
|
||||||
1. **Component Library Integration**
|
|
||||||
- Auto-discovered 153 KiCAD footprint libraries
|
|
||||||
- Full search, list, and find functionality
|
|
||||||
- Supports both `Library:Footprint` and `Footprint` formats
|
|
||||||
- Component placement working end-to-end
|
|
||||||
|
|
||||||
2. **Routing Operations**
|
|
||||||
- All routing commands tested with KiCAD 9.0
|
|
||||||
- Fixed 6 API compatibility issues
|
|
||||||
- Nets, traces, vias, copper pours all working
|
|
||||||
- Comprehensive testing completed
|
|
||||||
|
|
||||||
3. **Real-time Collaboration**
|
|
||||||
- Tested MCP→UI workflow (AI places, human sees)
|
|
||||||
- Tested UI→MCP workflow (human edits, AI reads)
|
|
||||||
- Both directions confirmed working
|
|
||||||
- Documentation created with best practices
|
|
||||||
|
|
||||||
4. **KiCAD 9.0 Compatibility**
|
|
||||||
- All API breaking changes identified and fixed
|
|
||||||
- `EDA_ANGLE`, `NetsByName`, zone APIs updated
|
|
||||||
- No known API issues remaining
|
|
||||||
|
|
||||||
5. **JLCPCB Integration Planning**
|
|
||||||
- Researched official JLCPCB API
|
|
||||||
- Designed complete implementation architecture
|
|
||||||
- Ready to implement (~3-4 days estimated)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Learning Resources
|
|
||||||
|
|
||||||
**For Users:**
|
|
||||||
1. Start with [README.md](../README.md) - Installation and quick start
|
|
||||||
2. Read [LIBRARY_INTEGRATION.md](LIBRARY_INTEGRATION.md) - Using footprint libraries
|
|
||||||
3. Read [REALTIME_WORKFLOW.md](REALTIME_WORKFLOW.md) - AI-human collaboration
|
|
||||||
4. Try example: "Place a 10k resistor at 50, 40mm using 0603 footprint"
|
|
||||||
5. Check [KNOWN_ISSUES.md](KNOWN_ISSUES.md) if you hit problems
|
|
||||||
|
|
||||||
**For Developers:**
|
|
||||||
1. Read [BUILD_AND_TEST_SESSION.md](BUILD_AND_TEST_SESSION.md) - Build setup
|
|
||||||
2. Check [ROADMAP.md](ROADMAP.md) - See what's coming next
|
|
||||||
3. Review [LIBRARY_INTEGRATION.md](LIBRARY_INTEGRATION.md) - Library system internals
|
|
||||||
4. See [JLCPCB_INTEGRATION_PLAN.md](JLCPCB_INTEGRATION_PLAN.md) - Next feature to build
|
|
||||||
5. Pick a task and contribute!
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## What's Next?
|
## What's Next?
|
||||||
|
|
||||||
### Immediate (Week 2 Completion)
|
### Immediate Priorities
|
||||||
1. **JLCPCB Parts Integration** (3-4 days)
|
1. **Complete IPC Testing** - Verify all 21 IPC handlers work correctly
|
||||||
- Download and cache ~108k parts database
|
2. **Fix Edge Cases** - Address any issues found during testing
|
||||||
- Parametric search (resistance, package, price)
|
3. **Improve Error Handling** - Better fallback behavior
|
||||||
- Map JLCPCB parts → KiCAD footprints
|
|
||||||
- Enable cost-optimized component selection
|
|
||||||
|
|
||||||
### Next Phase (Week 3)
|
### Planned Features
|
||||||
2. **IPC Backend Implementation** (1 week)
|
- JLCPCB parts integration
|
||||||
- Replace file I/O with IPC socket communication
|
- Digikey API integration
|
||||||
- Enable real-time UI updates (<100ms latency)
|
- Advanced routing algorithms
|
||||||
- Fix zone filling (no more SWIG segfaults)
|
- Smart BOM management
|
||||||
- True paired programming experience
|
- Design pattern library (Arduino shields, RPi HATs)
|
||||||
|
|
||||||
### Polish (Week 4+)
|
|
||||||
3. Example projects and tutorials
|
|
||||||
4. Windows/macOS testing
|
|
||||||
5. Performance optimization
|
|
||||||
6. v2.0 stable release preparation
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Call to Action
|
## Getting Help
|
||||||
|
|
||||||
**Ready to use it?**
|
**For Users:**
|
||||||
1. Follow [installation guide](../README.md#installation)
|
1. Check [README.md](../README.md) for installation
|
||||||
2. Try placing components: "Place a 10k 0603 resistor at 50, 40mm"
|
2. Review [KNOWN_ISSUES.md](KNOWN_ISSUES.md) for common problems
|
||||||
3. Test real-time collaboration workflow
|
3. Check logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
||||||
4. Report any issues you find
|
|
||||||
|
|
||||||
**Want to contribute?**
|
**For Developers:**
|
||||||
1. Check [ROADMAP.md](ROADMAP.md) for priorities
|
1. Read [BUILD_AND_TEST_SESSION.md](BUILD_AND_TEST_SESSION.md)
|
||||||
2. JLCPCB integration is ready to implement
|
2. Check [ROADMAP.md](ROADMAP.md) for priorities
|
||||||
3. Help test on Windows/macOS
|
3. Review [IPC_BACKEND_STATUS.md](IPC_BACKEND_STATUS.md) for IPC details
|
||||||
4. Open a PR!
|
|
||||||
|
|
||||||
**Need help?**
|
**Issues:**
|
||||||
- Check documentation (now with 11 comprehensive guides!)
|
- Open an issue on GitHub with OS, KiCAD version, and error details
|
||||||
- Review logs: `~/.kicad-mcp/logs/kicad_interface.log`
|
|
||||||
- Open an issue on GitHub
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Bottom Line:** Week 2 is 80% complete with major features working! Component placement, routing, and real-time collaboration all functional. JLCPCB integration planned, IPC backend next. On track for production-ready v2.0 release.
|
*Last Updated: 2025-12-02*
|
||||||
|
|
||||||
**Confidence Level:** Very High - Exceeding expectations
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last Updated: 2025-11-01*
|
|
||||||
*Maintained by: KiCAD MCP Team*
|
*Maintained by: KiCAD MCP Team*
|
||||||
|
|||||||
@@ -464,6 +464,207 @@ class IPCBoardAPI(BoardAPI):
|
|||||||
Place a component on the board.
|
Place a component on the board.
|
||||||
|
|
||||||
The component appears immediately in the KiCAD UI.
|
The component appears immediately in the KiCAD UI.
|
||||||
|
|
||||||
|
This method uses a hybrid approach:
|
||||||
|
1. Load the footprint definition from the library using pcbnew (SWIG)
|
||||||
|
2. Place it on the board via IPC for real-time UI updates
|
||||||
|
|
||||||
|
Args:
|
||||||
|
reference: Component reference designator (e.g., "R1", "U1")
|
||||||
|
footprint: Footprint path in format "Library:FootprintName" or just "FootprintName"
|
||||||
|
x: X position in mm
|
||||||
|
y: Y position in mm
|
||||||
|
rotation: Rotation angle in degrees
|
||||||
|
layer: Layer name ("F.Cu" for top, "B.Cu" for bottom)
|
||||||
|
value: Component value (optional)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# First, try to load the footprint from library using pcbnew SWIG
|
||||||
|
loaded_fp = self._load_footprint_from_library(footprint)
|
||||||
|
|
||||||
|
if loaded_fp:
|
||||||
|
# We have the footprint from the library - place it via SWIG
|
||||||
|
# then sync to IPC for UI update
|
||||||
|
return self._place_loaded_footprint(
|
||||||
|
loaded_fp, reference, x, y, rotation, layer, value
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Fallback: Create a basic placeholder footprint via IPC
|
||||||
|
logger.warning(f"Could not load footprint '{footprint}' from library, creating placeholder")
|
||||||
|
return self._place_placeholder_footprint(
|
||||||
|
reference, footprint, x, y, rotation, layer, value
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to place component: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _load_footprint_from_library(self, footprint_path: str):
|
||||||
|
"""
|
||||||
|
Load a footprint from the library using pcbnew SWIG API.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
footprint_path: Either "Library:FootprintName" or just "FootprintName"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
pcbnew.FOOTPRINT object or None if not found
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import pcbnew
|
||||||
|
|
||||||
|
# Parse library and footprint name
|
||||||
|
if ':' in footprint_path:
|
||||||
|
lib_name, fp_name = footprint_path.split(':', 1)
|
||||||
|
else:
|
||||||
|
# Try to find the footprint in all libraries
|
||||||
|
lib_name = None
|
||||||
|
fp_name = footprint_path
|
||||||
|
|
||||||
|
# Get the footprint library table
|
||||||
|
fp_lib_table = pcbnew.GetGlobalFootprintLib()
|
||||||
|
|
||||||
|
if lib_name:
|
||||||
|
# Load from specific library
|
||||||
|
try:
|
||||||
|
loaded_fp = pcbnew.FootprintLoad(fp_lib_table, lib_name, fp_name)
|
||||||
|
if loaded_fp:
|
||||||
|
logger.info(f"Loaded footprint '{fp_name}' from library '{lib_name}'")
|
||||||
|
return loaded_fp
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Could not load from {lib_name}: {e}")
|
||||||
|
else:
|
||||||
|
# Search all libraries for the footprint
|
||||||
|
lib_names = fp_lib_table.GetLogicalLibs()
|
||||||
|
for lib in lib_names:
|
||||||
|
try:
|
||||||
|
loaded_fp = pcbnew.FootprintLoad(fp_lib_table, lib, fp_name)
|
||||||
|
if loaded_fp:
|
||||||
|
logger.info(f"Found footprint '{fp_name}' in library '{lib}'")
|
||||||
|
return loaded_fp
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.warning(f"Footprint '{footprint_path}' not found in any library")
|
||||||
|
return None
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
logger.warning("pcbnew not available - cannot load footprints from library")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error loading footprint from library: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _place_loaded_footprint(
|
||||||
|
self,
|
||||||
|
loaded_fp,
|
||||||
|
reference: str,
|
||||||
|
x: float,
|
||||||
|
y: float,
|
||||||
|
rotation: float,
|
||||||
|
layer: str,
|
||||||
|
value: str
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Place a loaded pcbnew footprint onto the board.
|
||||||
|
|
||||||
|
Uses SWIG to add the footprint, then notifies for IPC sync.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import pcbnew
|
||||||
|
|
||||||
|
# Get the board file path from IPC to load via pcbnew
|
||||||
|
board = self._get_board()
|
||||||
|
|
||||||
|
# Get the pcbnew board instance
|
||||||
|
# We need to get the actual board file path
|
||||||
|
project = board.get_project()
|
||||||
|
board_path = None
|
||||||
|
|
||||||
|
# Try to get the board path from kipy
|
||||||
|
try:
|
||||||
|
docs = self._kicad.get_open_documents()
|
||||||
|
for doc in docs:
|
||||||
|
if hasattr(doc, 'path') and str(doc.path).endswith('.kicad_pcb'):
|
||||||
|
board_path = str(doc.path)
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Could not get board path from IPC: {e}")
|
||||||
|
|
||||||
|
if board_path and os.path.exists(board_path):
|
||||||
|
# Load board via pcbnew
|
||||||
|
pcb_board = pcbnew.LoadBoard(board_path)
|
||||||
|
else:
|
||||||
|
# Try to get from pcbnew directly
|
||||||
|
pcb_board = pcbnew.GetBoard()
|
||||||
|
|
||||||
|
if not pcb_board:
|
||||||
|
logger.error("Could not get pcbnew board instance")
|
||||||
|
return self._place_placeholder_footprint(
|
||||||
|
reference, "", x, y, rotation, layer, value
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set footprint position and properties
|
||||||
|
scale = MM_TO_NM
|
||||||
|
loaded_fp.SetPosition(pcbnew.VECTOR2I(int(x * scale), int(y * scale)))
|
||||||
|
loaded_fp.SetOrientationDegrees(rotation)
|
||||||
|
|
||||||
|
# Set reference
|
||||||
|
loaded_fp.SetReference(reference)
|
||||||
|
|
||||||
|
# Set value if provided
|
||||||
|
if value:
|
||||||
|
loaded_fp.SetValue(value)
|
||||||
|
|
||||||
|
# Set layer (flip if bottom)
|
||||||
|
if layer == "B.Cu":
|
||||||
|
if not loaded_fp.IsFlipped():
|
||||||
|
loaded_fp.Flip(loaded_fp.GetPosition(), False)
|
||||||
|
|
||||||
|
# Add to board
|
||||||
|
pcb_board.Add(loaded_fp)
|
||||||
|
|
||||||
|
# Save the board so IPC can see the changes
|
||||||
|
pcbnew.SaveBoard(board_path, pcb_board)
|
||||||
|
|
||||||
|
# Refresh IPC view
|
||||||
|
try:
|
||||||
|
board.revert() # Reload from disk to sync IPC
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Could not refresh IPC board: {e}")
|
||||||
|
|
||||||
|
self._notify("component_placed", {
|
||||||
|
"reference": reference,
|
||||||
|
"footprint": loaded_fp.GetFPIDAsString(),
|
||||||
|
"position": {"x": x, "y": y},
|
||||||
|
"rotation": rotation,
|
||||||
|
"layer": layer,
|
||||||
|
"loaded_from_library": True
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info(f"Placed component {reference} ({loaded_fp.GetFPIDAsString()}) at ({x}, {y}) mm")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error placing loaded footprint: {e}")
|
||||||
|
# Fall back to placeholder
|
||||||
|
return self._place_placeholder_footprint(
|
||||||
|
reference, "", x, y, rotation, layer, value
|
||||||
|
)
|
||||||
|
|
||||||
|
def _place_placeholder_footprint(
|
||||||
|
self,
|
||||||
|
reference: str,
|
||||||
|
footprint: str,
|
||||||
|
x: float,
|
||||||
|
y: float,
|
||||||
|
rotation: float,
|
||||||
|
layer: str,
|
||||||
|
value: str
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Place a placeholder footprint when library loading fails.
|
||||||
|
|
||||||
|
Creates a basic footprint via IPC with just reference/value fields.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from kipy.board_types import Footprint
|
from kipy.board_types import Footprint
|
||||||
@@ -487,12 +688,8 @@ class IPCBoardAPI(BoardAPI):
|
|||||||
# Set reference and value
|
# Set reference and value
|
||||||
if fp.reference_field:
|
if fp.reference_field:
|
||||||
fp.reference_field.text.value = reference
|
fp.reference_field.text.value = reference
|
||||||
if fp.value_field and value:
|
if fp.value_field:
|
||||||
fp.value_field.text.value = value
|
fp.value_field.text.value = value if value else footprint
|
||||||
|
|
||||||
# Note: Loading footprint from library requires additional handling
|
|
||||||
# The IPC API may need the footprint definition to be set
|
|
||||||
# For now, we create a basic footprint placeholder
|
|
||||||
|
|
||||||
# Begin transaction
|
# Begin transaction
|
||||||
commit = board.begin_commit()
|
commit = board.begin_commit()
|
||||||
@@ -504,14 +701,16 @@ class IPCBoardAPI(BoardAPI):
|
|||||||
"footprint": footprint,
|
"footprint": footprint,
|
||||||
"position": {"x": x, "y": y},
|
"position": {"x": x, "y": y},
|
||||||
"rotation": rotation,
|
"rotation": rotation,
|
||||||
"layer": layer
|
"layer": layer,
|
||||||
|
"loaded_from_library": False,
|
||||||
|
"is_placeholder": True
|
||||||
})
|
})
|
||||||
|
|
||||||
logger.info(f"Placed component {reference} at ({x}, {y}) mm")
|
logger.info(f"Placed placeholder component {reference} at ({x}, {y}) mm")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to place component: {e}")
|
logger.error(f"Failed to place placeholder component: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def move_component(self, reference: str, x: float, y: float, rotation: Optional[float] = None) -> bool:
|
def move_component(self, reference: str, x: float, y: float, rotation: Optional[float] = None) -> bool:
|
||||||
@@ -857,6 +1056,145 @@ class IPCBoardAPI(BoardAPI):
|
|||||||
logger.error(f"Failed to get nets: {e}")
|
logger.error(f"Failed to get nets: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def add_zone(
|
||||||
|
self,
|
||||||
|
points: List[Dict[str, float]],
|
||||||
|
layer: str = "F.Cu",
|
||||||
|
net_name: Optional[str] = None,
|
||||||
|
clearance: float = 0.5,
|
||||||
|
min_thickness: float = 0.25,
|
||||||
|
priority: int = 0,
|
||||||
|
fill_mode: str = "solid",
|
||||||
|
name: str = ""
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Add a copper pour zone to the board.
|
||||||
|
|
||||||
|
The zone appears immediately in the KiCAD UI.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
points: List of points defining the zone outline, e.g. [{"x": 0, "y": 0}, ...]
|
||||||
|
layer: Layer name (F.Cu, B.Cu, etc.)
|
||||||
|
net_name: Net to connect the zone to (e.g., "GND")
|
||||||
|
clearance: Clearance from other copper in mm
|
||||||
|
min_thickness: Minimum copper thickness in mm
|
||||||
|
priority: Zone priority (higher = fills first)
|
||||||
|
fill_mode: "solid" or "hatched"
|
||||||
|
name: Optional zone name
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from kipy.board_types import Zone, ZoneFillMode, ZoneType
|
||||||
|
from kipy.geometry import PolyLine, PolyLineNode, Vector2
|
||||||
|
from kipy.util.units import from_mm
|
||||||
|
from kipy.proto.board.board_types_pb2 import BoardLayer
|
||||||
|
|
||||||
|
board = self._get_board()
|
||||||
|
|
||||||
|
if len(points) < 3:
|
||||||
|
logger.error("Zone requires at least 3 points")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Create zone
|
||||||
|
zone = Zone()
|
||||||
|
zone.type = ZoneType.ZT_COPPER
|
||||||
|
|
||||||
|
# Set layer
|
||||||
|
layer_map = {
|
||||||
|
"F.Cu": BoardLayer.BL_F_Cu,
|
||||||
|
"B.Cu": BoardLayer.BL_B_Cu,
|
||||||
|
"In1.Cu": BoardLayer.BL_In1_Cu,
|
||||||
|
"In2.Cu": BoardLayer.BL_In2_Cu,
|
||||||
|
"In3.Cu": BoardLayer.BL_In3_Cu,
|
||||||
|
"In4.Cu": BoardLayer.BL_In4_Cu,
|
||||||
|
}
|
||||||
|
zone.layers = [layer_map.get(layer, BoardLayer.BL_F_Cu)]
|
||||||
|
|
||||||
|
# Set net if specified
|
||||||
|
if net_name:
|
||||||
|
nets = board.get_nets()
|
||||||
|
for net in nets:
|
||||||
|
if net.name == net_name:
|
||||||
|
zone.net = net
|
||||||
|
break
|
||||||
|
|
||||||
|
# Set zone properties
|
||||||
|
zone.clearance = from_mm(clearance)
|
||||||
|
zone.min_thickness = from_mm(min_thickness)
|
||||||
|
zone.priority = priority
|
||||||
|
|
||||||
|
if name:
|
||||||
|
zone.name = name
|
||||||
|
|
||||||
|
# Set fill mode
|
||||||
|
if fill_mode == "hatched":
|
||||||
|
zone.fill_mode = ZoneFillMode.ZFM_HATCHED
|
||||||
|
else:
|
||||||
|
zone.fill_mode = ZoneFillMode.ZFM_SOLID
|
||||||
|
|
||||||
|
# Create outline polyline
|
||||||
|
outline = PolyLine()
|
||||||
|
outline.closed = True
|
||||||
|
|
||||||
|
for point in points:
|
||||||
|
x = point.get("x", 0)
|
||||||
|
y = point.get("y", 0)
|
||||||
|
node = PolyLineNode.from_xy(from_mm(x), from_mm(y))
|
||||||
|
outline.append(node)
|
||||||
|
|
||||||
|
# Set the outline on the zone
|
||||||
|
# Note: Zone outline is set via the proto directly since kipy
|
||||||
|
# doesn't expose a direct setter for creating new zones
|
||||||
|
zone._proto.outline.polygons.add()
|
||||||
|
zone._proto.outline.polygons[0].outline.CopyFrom(outline._proto)
|
||||||
|
|
||||||
|
# Add zone with transaction
|
||||||
|
commit = board.begin_commit()
|
||||||
|
board.create_items(zone)
|
||||||
|
board.push_commit(commit, f"Added copper zone on {layer}")
|
||||||
|
|
||||||
|
self._notify("zone_added", {
|
||||||
|
"layer": layer,
|
||||||
|
"net": net_name,
|
||||||
|
"points": len(points),
|
||||||
|
"priority": priority
|
||||||
|
})
|
||||||
|
|
||||||
|
logger.info(f"Added zone on {layer} with {len(points)} points")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to add zone: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_zones(self) -> List[Dict[str, Any]]:
|
||||||
|
"""Get all zones on the board."""
|
||||||
|
try:
|
||||||
|
from kipy.util.units import to_mm
|
||||||
|
|
||||||
|
board = self._get_board()
|
||||||
|
zones = board.get_zones()
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for zone in zones:
|
||||||
|
try:
|
||||||
|
result.append({
|
||||||
|
"name": zone.name if hasattr(zone, 'name') else "",
|
||||||
|
"net": zone.net.name if zone.net else "",
|
||||||
|
"priority": zone.priority if hasattr(zone, 'priority') else 0,
|
||||||
|
"layers": [str(l) for l in zone.layers] if hasattr(zone, 'layers') else [],
|
||||||
|
"filled": zone.filled if hasattr(zone, 'filled') else False,
|
||||||
|
"id": str(zone.id) if hasattr(zone, 'id') else ""
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Error processing zone: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to get zones: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
def refill_zones(self) -> bool:
|
def refill_zones(self) -> bool:
|
||||||
"""Refill all copper pour zones."""
|
"""Refill all copper pour zones."""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -302,7 +302,8 @@ class KiCADInterface:
|
|||||||
"create_netclass": self.routing_commands.create_netclass,
|
"create_netclass": self.routing_commands.create_netclass,
|
||||||
"add_copper_pour": self.routing_commands.add_copper_pour,
|
"add_copper_pour": self.routing_commands.add_copper_pour,
|
||||||
"route_differential_pair": self.routing_commands.route_differential_pair,
|
"route_differential_pair": self.routing_commands.route_differential_pair,
|
||||||
|
"refill_zones": self._handle_refill_zones,
|
||||||
|
|
||||||
# Design rule commands
|
# Design rule commands
|
||||||
"set_design_rules": self.design_rule_commands.set_design_rules,
|
"set_design_rules": self.design_rule_commands.set_design_rules,
|
||||||
"get_design_rules": self.design_rule_commands.get_design_rules,
|
"get_design_rules": self.design_rule_commands.get_design_rules,
|
||||||
@@ -358,16 +359,26 @@ class KiCADInterface:
|
|||||||
"route_trace": "_ipc_route_trace",
|
"route_trace": "_ipc_route_trace",
|
||||||
"add_via": "_ipc_add_via",
|
"add_via": "_ipc_add_via",
|
||||||
"add_net": "_ipc_add_net",
|
"add_net": "_ipc_add_net",
|
||||||
|
"delete_trace": "_ipc_delete_trace",
|
||||||
|
"get_nets_list": "_ipc_get_nets_list",
|
||||||
|
# Zone commands
|
||||||
|
"add_copper_pour": "_ipc_add_copper_pour",
|
||||||
|
"refill_zones": "_ipc_refill_zones",
|
||||||
# Board commands
|
# Board commands
|
||||||
"add_text": "_ipc_add_text",
|
"add_text": "_ipc_add_text",
|
||||||
"add_board_text": "_ipc_add_text",
|
"add_board_text": "_ipc_add_text",
|
||||||
"set_board_size": "_ipc_set_board_size",
|
"set_board_size": "_ipc_set_board_size",
|
||||||
"get_board_info": "_ipc_get_board_info",
|
"get_board_info": "_ipc_get_board_info",
|
||||||
|
"add_board_outline": "_ipc_add_board_outline",
|
||||||
|
"add_mounting_hole": "_ipc_add_mounting_hole",
|
||||||
|
"get_layer_list": "_ipc_get_layer_list",
|
||||||
# Component commands
|
# Component commands
|
||||||
"place_component": "_ipc_place_component",
|
"place_component": "_ipc_place_component",
|
||||||
"move_component": "_ipc_move_component",
|
"move_component": "_ipc_move_component",
|
||||||
|
"rotate_component": "_ipc_rotate_component",
|
||||||
"delete_component": "_ipc_delete_component",
|
"delete_component": "_ipc_delete_component",
|
||||||
"get_component_list": "_ipc_get_component_list",
|
"get_component_list": "_ipc_get_component_list",
|
||||||
|
"get_component_properties": "_ipc_get_component_properties",
|
||||||
# Save command
|
# Save command
|
||||||
"save_project": "_ipc_save_project",
|
"save_project": "_ipc_save_project",
|
||||||
}
|
}
|
||||||
@@ -454,18 +465,38 @@ class KiCADInterface:
|
|||||||
"""Create a new schematic"""
|
"""Create a new schematic"""
|
||||||
logger.info("Creating schematic")
|
logger.info("Creating schematic")
|
||||||
try:
|
try:
|
||||||
# Accept both 'name' (from MCP tool) and 'projectName' (legacy)
|
# Support multiple parameter naming conventions for compatibility:
|
||||||
project_name = params.get("name") or params.get("projectName")
|
# - TypeScript tools use: name, path
|
||||||
path = params.get("path", ".")
|
# - Python schema uses: filename, title
|
||||||
|
# - Legacy uses: projectName, path, metadata
|
||||||
|
project_name = (
|
||||||
|
params.get("projectName") or
|
||||||
|
params.get("name") or
|
||||||
|
params.get("title")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Handle filename parameter - it may contain full path
|
||||||
|
filename = params.get("filename")
|
||||||
|
if filename:
|
||||||
|
# If filename provided, extract name and path from it
|
||||||
|
if filename.endswith('.kicad_sch'):
|
||||||
|
filename = filename[:-10] # Remove .kicad_sch extension
|
||||||
|
path = os.path.dirname(filename) or "."
|
||||||
|
project_name = project_name or os.path.basename(filename)
|
||||||
|
else:
|
||||||
|
path = params.get("path", ".")
|
||||||
metadata = params.get("metadata", {})
|
metadata = params.get("metadata", {})
|
||||||
|
|
||||||
if not project_name:
|
if not project_name:
|
||||||
return {"success": False, "message": "Project name is required"}
|
return {
|
||||||
|
"success": False,
|
||||||
|
"message": "Schematic name is required. Provide 'name', 'projectName', or 'filename' parameter."
|
||||||
|
}
|
||||||
|
|
||||||
schematic = SchematicManager.create_schematic(project_name, metadata)
|
schematic = SchematicManager.create_schematic(project_name, metadata)
|
||||||
file_path = f"{path}/{project_name}.kicad_sch"
|
file_path = f"{path}/{project_name}.kicad_sch"
|
||||||
success = SchematicManager.save_schematic(schematic, file_path)
|
success = SchematicManager.save_schematic(schematic, file_path)
|
||||||
|
|
||||||
return {"success": success, "file_path": file_path}
|
return {"success": success, "file_path": file_path}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error creating schematic: {str(e)}")
|
logger.error(f"Error creating schematic: {str(e)}")
|
||||||
@@ -747,6 +778,31 @@ class KiCADInterface:
|
|||||||
logger.error(f"Error launching KiCAD UI: {str(e)}")
|
logger.error(f"Error launching KiCAD UI: {str(e)}")
|
||||||
return {"success": False, "message": str(e)}
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _handle_refill_zones(self, params):
|
||||||
|
"""Refill all copper pour zones on the board"""
|
||||||
|
logger.info("Refilling zones")
|
||||||
|
try:
|
||||||
|
if not self.board:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"message": "No board is loaded",
|
||||||
|
"errorDetails": "Load or create a board first"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Use pcbnew's zone filler for SWIG backend
|
||||||
|
filler = pcbnew.ZONE_FILLER(self.board)
|
||||||
|
zones = self.board.Zones()
|
||||||
|
filler.Fill(zones)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": "Zones refilled successfully",
|
||||||
|
"zoneCount": zones.size() if hasattr(zones, 'size') else len(list(zones))
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error refilling zones: {str(e)}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# IPC Backend handlers - these provide real-time UI synchronization
|
# IPC Backend handlers - these provide real-time UI synchronization
|
||||||
# These methods are called automatically when IPC is available
|
# These methods are called automatically when IPC is available
|
||||||
@@ -843,6 +899,73 @@ class KiCADInterface:
|
|||||||
"net": {"name": name}
|
"net": {"name": name}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _ipc_add_copper_pour(self, params):
|
||||||
|
"""IPC handler for add_copper_pour - adds zone with real-time UI update"""
|
||||||
|
try:
|
||||||
|
layer = params.get("layer", "F.Cu")
|
||||||
|
net = params.get("net")
|
||||||
|
clearance = params.get("clearance", 0.5)
|
||||||
|
min_width = params.get("minWidth", 0.25)
|
||||||
|
points = params.get("points", [])
|
||||||
|
priority = params.get("priority", 0)
|
||||||
|
fill_type = params.get("fillType", "solid")
|
||||||
|
name = params.get("name", "")
|
||||||
|
|
||||||
|
if not points or len(points) < 3:
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"message": "At least 3 points are required for copper pour outline"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert points format if needed (handle both {x, y} and {x, y, unit})
|
||||||
|
formatted_points = []
|
||||||
|
for point in points:
|
||||||
|
formatted_points.append({
|
||||||
|
"x": point.get("x", 0),
|
||||||
|
"y": point.get("y", 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
success = self.ipc_board_api.add_zone(
|
||||||
|
points=formatted_points,
|
||||||
|
layer=layer,
|
||||||
|
net_name=net,
|
||||||
|
clearance=clearance,
|
||||||
|
min_thickness=min_width,
|
||||||
|
priority=priority,
|
||||||
|
fill_mode=fill_type,
|
||||||
|
name=name
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": success,
|
||||||
|
"message": "Added copper pour (visible in KiCAD UI)" if success else "Failed to add copper pour",
|
||||||
|
"pour": {
|
||||||
|
"layer": layer,
|
||||||
|
"net": net,
|
||||||
|
"clearance": clearance,
|
||||||
|
"minWidth": min_width,
|
||||||
|
"priority": priority,
|
||||||
|
"fillType": fill_type,
|
||||||
|
"pointCount": len(points)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC add_copper_pour error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_refill_zones(self, params):
|
||||||
|
"""IPC handler for refill_zones - refills all zones with real-time UI update"""
|
||||||
|
try:
|
||||||
|
success = self.ipc_board_api.refill_zones()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": success,
|
||||||
|
"message": "Zones refilled (visible in KiCAD UI)" if success else "Failed to refill zones"
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC refill_zones error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
def _ipc_add_text(self, params):
|
def _ipc_add_text(self, params):
|
||||||
"""IPC handler for add_text/add_board_text - adds text with real-time UI update"""
|
"""IPC handler for add_text/add_board_text - adds text with real-time UI update"""
|
||||||
try:
|
try:
|
||||||
@@ -1017,6 +1140,184 @@ class KiCADInterface:
|
|||||||
logger.error(f"IPC save_project error: {e}")
|
logger.error(f"IPC save_project error: {e}")
|
||||||
return {"success": False, "message": str(e)}
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_delete_trace(self, params):
|
||||||
|
"""IPC handler for delete_trace - Note: IPC doesn't support direct trace deletion yet"""
|
||||||
|
# IPC API doesn't have a direct delete track method
|
||||||
|
# Fall back to SWIG for this operation
|
||||||
|
logger.info("delete_trace: Falling back to SWIG (IPC doesn't support trace deletion)")
|
||||||
|
return self.routing_commands.delete_trace(params)
|
||||||
|
|
||||||
|
def _ipc_get_nets_list(self, params):
|
||||||
|
"""IPC handler for get_nets_list - gets nets with real-time data"""
|
||||||
|
try:
|
||||||
|
nets = self.ipc_board_api.get_nets()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"nets": nets,
|
||||||
|
"count": len(nets)
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC get_nets_list error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_add_board_outline(self, params):
|
||||||
|
"""IPC handler for add_board_outline - adds board edge with real-time UI update"""
|
||||||
|
try:
|
||||||
|
from kipy.board_types import BoardSegment
|
||||||
|
from kipy.geometry import Vector2
|
||||||
|
from kipy.util.units import from_mm
|
||||||
|
from kipy.proto.board.board_types_pb2 import BoardLayer
|
||||||
|
|
||||||
|
board = self.ipc_board_api._get_board()
|
||||||
|
|
||||||
|
points = params.get("points", [])
|
||||||
|
width = params.get("width", 0.1)
|
||||||
|
|
||||||
|
if len(points) < 2:
|
||||||
|
return {"success": False, "message": "At least 2 points required for board outline"}
|
||||||
|
|
||||||
|
commit = board.begin_commit()
|
||||||
|
lines_created = 0
|
||||||
|
|
||||||
|
# Create line segments connecting the points
|
||||||
|
for i in range(len(points)):
|
||||||
|
start = points[i]
|
||||||
|
end = points[(i + 1) % len(points)] # Wrap around to close the outline
|
||||||
|
|
||||||
|
segment = BoardSegment()
|
||||||
|
segment.start = Vector2.from_xy(from_mm(start.get("x", 0)), from_mm(start.get("y", 0)))
|
||||||
|
segment.end = Vector2.from_xy(from_mm(end.get("x", 0)), from_mm(end.get("y", 0)))
|
||||||
|
segment.layer = BoardLayer.BL_Edge_Cuts
|
||||||
|
segment.attributes.stroke.width = from_mm(width)
|
||||||
|
|
||||||
|
board.create_items(segment)
|
||||||
|
lines_created += 1
|
||||||
|
|
||||||
|
board.push_commit(commit, "Added board outline")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": f"Added board outline with {lines_created} segments (visible in KiCAD UI)",
|
||||||
|
"segments": lines_created
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC add_board_outline error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_add_mounting_hole(self, params):
|
||||||
|
"""IPC handler for add_mounting_hole - adds mounting hole with real-time UI update"""
|
||||||
|
try:
|
||||||
|
from kipy.board_types import BoardCircle
|
||||||
|
from kipy.geometry import Vector2
|
||||||
|
from kipy.util.units import from_mm
|
||||||
|
from kipy.proto.board.board_types_pb2 import BoardLayer
|
||||||
|
|
||||||
|
board = self.ipc_board_api._get_board()
|
||||||
|
|
||||||
|
x = params.get("x", 0)
|
||||||
|
y = params.get("y", 0)
|
||||||
|
diameter = params.get("diameter", 3.2) # M3 hole default
|
||||||
|
|
||||||
|
commit = board.begin_commit()
|
||||||
|
|
||||||
|
# Create circle on Edge.Cuts layer for the hole
|
||||||
|
circle = BoardCircle()
|
||||||
|
circle.center = Vector2.from_xy(from_mm(x), from_mm(y))
|
||||||
|
circle.radius = from_mm(diameter / 2)
|
||||||
|
circle.layer = BoardLayer.BL_Edge_Cuts
|
||||||
|
circle.attributes.stroke.width = from_mm(0.1)
|
||||||
|
|
||||||
|
board.create_items(circle)
|
||||||
|
board.push_commit(commit, f"Added mounting hole at ({x}, {y})")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": f"Added mounting hole at ({x}, {y}) mm (visible in KiCAD UI)",
|
||||||
|
"hole": {
|
||||||
|
"position": {"x": x, "y": y},
|
||||||
|
"diameter": diameter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC add_mounting_hole error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_get_layer_list(self, params):
|
||||||
|
"""IPC handler for get_layer_list - gets enabled layers"""
|
||||||
|
try:
|
||||||
|
layers = self.ipc_board_api.get_enabled_layers()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"layers": layers,
|
||||||
|
"count": len(layers)
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC get_layer_list error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_rotate_component(self, params):
|
||||||
|
"""IPC handler for rotate_component - rotates component with real-time UI update"""
|
||||||
|
try:
|
||||||
|
reference = params.get("reference", params.get("componentId", ""))
|
||||||
|
angle = params.get("angle", params.get("rotation", 90))
|
||||||
|
|
||||||
|
# Get current component to find its position
|
||||||
|
components = self.ipc_board_api.list_components()
|
||||||
|
target = None
|
||||||
|
for comp in components:
|
||||||
|
if comp.get("reference") == reference:
|
||||||
|
target = comp
|
||||||
|
break
|
||||||
|
|
||||||
|
if not target:
|
||||||
|
return {"success": False, "message": f"Component {reference} not found"}
|
||||||
|
|
||||||
|
# Calculate new rotation
|
||||||
|
current_rotation = target.get("rotation", 0)
|
||||||
|
new_rotation = (current_rotation + angle) % 360
|
||||||
|
|
||||||
|
# Use move_component with new rotation (position stays the same)
|
||||||
|
success = self.ipc_board_api.move_component(
|
||||||
|
reference=reference,
|
||||||
|
x=target.get("position", {}).get("x", 0),
|
||||||
|
y=target.get("position", {}).get("y", 0),
|
||||||
|
rotation=new_rotation
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": success,
|
||||||
|
"message": f"Rotated component {reference} by {angle}° (visible in KiCAD UI)" if success else "Failed to rotate component",
|
||||||
|
"newRotation": new_rotation
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC rotate_component error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
|
def _ipc_get_component_properties(self, params):
|
||||||
|
"""IPC handler for get_component_properties - gets detailed component info"""
|
||||||
|
try:
|
||||||
|
reference = params.get("reference", params.get("componentId", ""))
|
||||||
|
|
||||||
|
components = self.ipc_board_api.list_components()
|
||||||
|
target = None
|
||||||
|
for comp in components:
|
||||||
|
if comp.get("reference") == reference:
|
||||||
|
target = comp
|
||||||
|
break
|
||||||
|
|
||||||
|
if not target:
|
||||||
|
return {"success": False, "message": f"Component {reference} not found"}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"component": target
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"IPC get_component_properties error: {e}")
|
||||||
|
return {"success": False, "message": str(e)}
|
||||||
|
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
# Legacy IPC command handlers (explicit ipc_* commands)
|
# Legacy IPC command handlers (explicit ipc_* commands)
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user