""" Power symbol placement tool for the mckicad MCP server. Attaches power rail symbols (GND, VCC, +3V3, etc.) to component pins with automatic reference numbering, direction detection, and wire stubs. Uses the shared geometry helpers from the patterns library. """ import logging from typing import Any from mckicad.server import mcp from mckicad.utils.sch_helpers import expand as _expand from mckicad.utils.sch_helpers import load_schematic, validate_schematic_path as _validate_schematic_path logger = logging.getLogger(__name__) def _get_schematic_engine() -> str: return "sch_document" @mcp.tool() def add_power_symbol( schematic_path: str, net: str, pin_ref: str, pin_number: str, lib_id: str | None = None, stub_length: float = 5.08, ) -> dict[str, Any]: """Attach a power symbol (GND, VCC, +3V3, etc.) to a component pin. Automatically determines the correct power library symbol from the net name, assigns a ``#PWR`` reference, places the symbol above (supply) or below (ground) the pin, and draws a connecting wire stub. KiCad's connectivity engine treats a power symbol at a pin coordinate as a direct electrical connection — no wire is required. This tool places the symbol *offset* from the pin for visual clarity and draws an explicit wire stub bridging the gap. This is the recommended way to connect power rails to component pins -- it handles direction, grid alignment, and reference numbering for you. For bulk power connections, see ``apply_batch`` (power_symbols section) or the pattern tools (``place_decoupling_bank_pattern``, etc.). Args: schematic_path: Path to an existing .kicad_sch file. net: Power net name, e.g. ``GND``, ``+3V3``, ``VCC``, ``+5V``. The corresponding ``power:`` library symbol is auto-detected. pin_ref: Reference designator of the target component (e.g. ``C1``, ``U3``). pin_number: Pin number on the target component (e.g. ``1``, ``2``). lib_id: Override the auto-detected power symbol library ID. Only needed for non-standard symbols not in KiCad's power library. stub_length: Wire stub length in mm between pin and symbol. Defaults to 5.08 (2 grid units). Returns: Dictionary with ``success``, placed ``reference``, ``lib_id``, symbol position, wire ID, and direction. """ verr = _validate_schematic_path(schematic_path) if verr: return verr schematic_path = _expand(schematic_path) if not net: return {"success": False, "error": "net must be a non-empty string"} if not pin_ref: return {"success": False, "error": "pin_ref must be a non-empty string"} if not pin_number: return {"success": False, "error": "pin_number must be a non-empty string"} try: from mckicad.patterns._geometry import add_power_symbol_to_pin from mckicad.utils.sexp_parser import resolve_pin_position sch = load_schematic(schematic_path) # Look up the target pin position (with sexp fallback for custom symbols) pin_pos_tuple = resolve_pin_position(sch, schematic_path, pin_ref, pin_number) if pin_pos_tuple is None: return { "success": False, "error": ( f"Could not find pin {pin_number} on component {pin_ref}. " f"Use get_component_pins to list available pins." ), "schematic_path": schematic_path, } result = add_power_symbol_to_pin( sch=sch, pin_position=pin_pos_tuple, net=net, lib_id=lib_id, stub_length=stub_length, ) sch.save(schematic_path) logger.info( "Added %s power symbol %s to %s pin %s in %s", net, result["reference"], pin_ref, pin_number, schematic_path, ) return { "success": True, **result, "target_component": pin_ref, "target_pin": pin_number, "schematic_path": schematic_path, "engine": _get_schematic_engine(), } except Exception as e: logger.error( "Failed to add power symbol %s to %s.%s in %s: %s", net, pin_ref, pin_number, schematic_path, e, ) return { "success": False, "error": str(e), "schematic_path": schematic_path, }