9 EasyEDA Pro API and MCP server: how they really behave¶
For anyone who calls EasyEDA Pro's API directly or wants to know why edakit's code looks the way it does. After this chapter you know how the API and the MCP server behave, and how edakit works around each point. The short way: Lay out the board.
The behaviour is that of EasyEDA Pro 3.2.206 (Linux) with easyeda-mcp-pro 1.4.0. A sentence starting "3.2.209:" is what the live check on EasyEDA Pro 3.2.209 found, each call checked against the JSDoc of the client's types first. What edakit wants instead, and how far upstream has got, is kept in upstream/README.md.
Calls go through the MCP tool easyeda_api_call with path (e.g. PCB_PrimitiveLine.create) and args (a list).
List the available methods with easyeda_api_inventory and a filter.
9.1 Server and bridge¶
| Topic | Behaviour |
|---|---|
easyeda_api_call |
Needs confirmWrite: true always, also for pure reads. easyeda_catalog_verify_device writes to the local catalogue and needs it too. |
| Several servers | A second server (e.g. the one an edakit command starts) uses the same bridge connection as Claude Code's server – nothing needs to be disconnected. |
| Bridge timeout | Default 15 s per call; DRC and pour fills of a large board take longer. BRIDGE_TIMEOUT_MS=120000 in mcp-server.sh; a server cuts its own calls short after its timeout. Until 1.6.0 the server that holds the bridge port dropped pending requests after its timeout ("stale sweep"), also requests another server passed through; since 1.7.0 each request keeps its own (M-1). After changing it, restart all easyeda-mcp-pro processes. |
| npx | Do not start the server through npx: npx does not pass SIGTERM on, the server lingers as an orphan and blocks port 49620. mcp-server.sh installs a pinned version once and runs node directly. |
| Return depth | easyeda_api_call cuts every answer after 5 levels ([MaxDepth]) unless maxDepth (1 to 16, since 1.7.0, M-3) asks for more. DRC details and the rule configuration are unreadable at 5; edakit asks 12 levels on every call (eda.API_DEPTH). Then PCB_Drc.check(true, false, true) returns every finding per category (Clearance Error, Connection Error, …) with errorObjType, ruleName, obj1/obj2 (typeName, suffix = "(net): eNNN"), errData (primitive ids, position, minDistance, layerIds). |
| Schematic PDF | easyeda_export_pdf with scope: "schematic" calls SCH_ManufactureData.getExportDocumentFile(name, "PDF") since 1.7.0 (M-2); until 1.6.0 it called PCB_ManufactureData.getPdfFile and returned nothing for a schematic. |
| BOM and netlist export | easyeda_bom_export writes no file and mixes all schematics of the project; the netlist export returns nothing. edakit writes both itself from the schematic primitives. |
| Exports | Export tools write only into the server's ARTIFACT_DIR; edakit starts its server with the directory it wants. The pick-and-place export returns csv since 1.7.0 (M-7); until 1.6.0 the bridge passed no file type and EasyEDA answered with xlsx – edakit reads either. |
| ODB++ | easyeda_export_odb (since 1.7.0, M-4) calls PCB_ManufactureData.getOpenDatabaseDoublePlusFile (BETA in EasyEDA Pro's API) with the unit inch and plated and non-plated holes; the server registers it only in the profile experimental, which edakit's own servers run (2.4). Until 1.6.0 edakit patched the tool into the server and the handler into the bridge. It serves a maker that assembles from ODB++ (ordering at the manufacturer, 8.4; SYNC.odb). Live (ordering step 0b, EasyEDA Pro 3.2.206, a probe board): the archive holds comp_+_top and comp_+_bot with package, pins and the device name – the MPN for LCSC parts, no LCSC number –, turns clockwise (90° in the CPL is 270°, on the bottom too, mirror N) and keeps a part kept out of EasyEDA's BOM without a mark; it equals the export by hand (File > Export > ODB++, "One Key Export") but for the unit – the API writes inch whatever unit says (its type admits ESYS_Unit.INCH only), the dialog mm – and 30 empty custom_layer folders. EasyEDA's tgz arrives in the ARTIFACT_DIR; edakit packs it into odb_<board>.zip and removes it. 3.2.209: the same – "mm" (ESYS_Unit.MILLIMETER) gives UNITS=INCH in every file of the archive; reported as a wish (#51). |
| Simulation tools | easyeda_simulate_operating_point / _transient know two diode models and no transistors – useless for a real circuit; edakit simulates with ngspice from the graph instead. |
| Part search | easyeda_schematic_search_device is a full-text search: C5613 also finds C5613331 and UC5613PWP. Take only hits whose supplierId is exactly the LCSC number. It returns no stock and no price. |
9.2 Editor state¶
| Topic | Behaviour |
|---|---|
| Active tab | Most tools act on the active document. If another tab is active, easyeda_schematic_sheet_info returns SHEET_INFO_UNAVAILABLE, and placing runs into the bridge timeout (unconfirmed: true) – check with a read whether something was placed after all. EasyEDA occasionally switches the tab by itself, so edakit checks the focus before writes (every write in the schematic, every 20 writes in the PCB) and gets the tab back or aborts. Reads of the focused page – easyeda_bom_generate, the page's parts and nets – count only when the page is still active after the answer (eda.read_on_page), otherwise the page is read again, three times at most – the bell reported the BOM tool mixing tabs, and a BOM of the template, which has the same parts, would pass SYNC.bom. Before the BOM the gate closes the other saved schematic tabs. Not run live yet. |
| Start page | Focus tab_page1 means EasyEDA shows its start page; then every DMT_* query returns null. Open the project with DMT_Project.openProject(<projectUuid>). |
| Local projects | DMT_Project.getAllProjectsUuid lists the local projects of one project folder, given as teamUuid – DMT_Team.getAllTeamsInfo lists the folders, each folder's path its uuid; without it the answer is [] by design. edakit finds a project by its name in every folder, and remembers its UUID once it saw it open. modifyProjectDescription and modifyProjectFriendlyName are placeholders (always false): @internal, suspended since 2024 (#48). |
| BOM | easyeda_bom_generate lists the parts of the focused schematic page, not of the board or the PCB. After a template run it returns the template's parts. The gate focuses every page of the board schematic in turn and merges the lists; since easyeda-mcp-pro 1.6.0 a board-linked schematic lists every part once, and SYNC.bom reports a designator listed twice. The schematic's parts are read page by page too: scope: "all_pages" of easyeda_schematic_components answers with the parts of every open schematic, the template's included, without their page. |
| Creating projects | DMT_Project.createProject returns null in the local desktop client: its local server wants a folder path that the API has no parameter for (EasyEDA's log: /api/client/createProject … 请求参数path错误, "path parameter wrong"). Create a new project by hand once. A command that goes on after a failed create writes into whatever project is open – edakit checks the open project's name before every run. 3.2.209: unchanged, also with the project folder as teamUuid – the API's handler builds its request with path: undefined (#45). |
| PCB tab "active" | The PCB editor answers PCB_Drc.check, getDsnFile and exports only after EasyEDA reported its tab as active – otherwise silently undefined/null. That report comes only on a tab switch; openDocument on the current tab does not help. Probe: PCB_Drc.getCurrentRuleConfigurationName (empty = inactive). Remedy: open the start page tab_page1, then the PCB again. 3.2.209: not seen again – after openDocument(pcb) the PCB answers at once; with the schematic active the probe throws ("指定的主题消息在对应的画布内没有相关订阅") instead of returning empty. |
| Throttling | Chromium throttles timers of covered windows; EasyEDA computes DRC, fills and exports in many small timer steps. With VS Code over EasyEDA the DRC of a 120-part board took more than 120 s and failed; unthrottled 1–4 s. Start EasyEDA with --disable-background-timer-throttling --disable-renderer-backgrounding --disable-backgrounding-occluded-windows. |
| ELECTRON_RUN_AS_NODE | Every shell started from VS Code inherits it; EasyEDA (Electron) started from there behaves like Node ("bad option: --no-sandbox"). Start with env -u ELECTRON_RUN_AS_NODE. |
| Crashes | Long runs and big batch_write blocks crashed EasyEDA twice with V8 out-of-memory. edakit writes 40 operations per call and prints EasyEDA's memory per phase. |
9.3 Schematic¶
| Topic | Behaviour |
|---|---|
| Schematics | DMT_Schematic.createSchematic() → UUID (with page P1), deleteSchematic(uuid), copySchematic(uuid) (complete; named <name>_1 afterwards), DMT_EditorControl.openDocument(pageUuid) activates a page. |
| Renaming | modifySchematicName(uuid, name) renames the active schematic, not the one passed. Right after createSchematic it reports true and does nothing. Once, after hours of runs, it answered false, then true without effect, in every project, until EasyEDA was restarted. Right after openProject, getAllSchematicsInfo and getAllBoardsInfo may still miss documents – a schematic just created is not listed yet; open_project waits until a board is listed, schematic create until its new schematic is. Once a rename meant for a schematic renamed the project's panel ("Panel1" → generated_esp32): rename_schematic compares the panels' names too, renames a panel back with DMT_Panel.modifyPanelName and stops. Activate the page first, rename, then check all names. Never delete anything when names look wrong – it might be the wrong schematic. 3.2.209: renames the schematic passed, also when another one is active; the docs' example opens the schematic first, waits 1.5 s and compares names ignoring case. 3.2.209: modifySchematicName and modifySchematicPageName look the UUID up in the rows of the project tree in the left panel (getLeftTreeContentData, bundle Hg.modifyName) and answer false when it is not there – and the tree holds its rows only once it was shown: after a start of EasyEDA with another tab in the left panel every rename answered false, in every project, until the project tree was opened once (E-17). SYS_PanelControl.openLeftPanel("projectDesign") would open it, but the bridge allows no SYS_ class. |
| Reading names | getAllSchematicsInfo returns names partly stale or lower-case – read each name with getSchematicInfo(uuid). Right after creation that throws reading 'Symbol' for a moment. |
| Board link | A schematic that belongs to a board (parentBoardName) must never be deleted or replaced: the PCB would lose its schematic. |
| Coordinates | y points up on screen (the tool says yAxis: down). Pin x/y = pin tip, pin rotation = direction pointing out (0 = +x, 90 = +y). Part rotation is counter-clockwise. |
| Moving | modify_primitive reports followedWireIds, but the wires stay where they were – the connection breaks. So: delete wires, move, draw again. |
| Net connections | connect_pins_by_net draws a short stub with the net name per pin – ERC and ratsnest see the connection. It silently skips a pin whose stub end would land on a point that already belongs to another net; a longer stub fixes it. |
| Flags | SCH_PrimitiveComponent.createNetFlag(kind, net, x, y, rot). Ground points to −y at 0, power to +y; the rotation turns clockwise. |
| Wires | SCH_PrimitiveWire.create([[x1,y1,x2,y2], …], net) – one wire may branch (junction dots at T joints automatically). A crossing with four branches → create failed!. Touching wires of the same net merge. |
batch_write |
Atomic per call; fails on merging wires and on modify without a change (cmdKey). A component create takes mirror, addIntoBom and addIntoPcb since 1.7.0 (M-9): the bridge calls SCH_PrimitiveComponent.create(deviceItem, x, y) and modifies them afterwards, best-effort – edakit reads the flag back. Until 1.6.0 it dropped them and still reported applied. EasyEDA's own create(…, mirror, addIntoBom, addIntoPcb) sets all three on 3.2.209. "Invalid device" means a device id LIB_Device.get does not know – a project instance's, not the search's. |
| Netlist after writes | Right after many writes easyeda_schematic_nets sometimes returns nothing (0/88 nets, two minutes later 88/88). Wait and read again. |
| ERC | Nets with one pin (partial builds) give warnings, not errors. |
| Texts | SCH_PrimitiveText.delete and .modify act only until the page is reloaded: only creating is saved. After every run another layer of titles and notes was on the page (100 texts on one sheet). SCH_PrimitiveCircle.delete([textIds]) (or …Component/…Wire.delete) deletes texts for good. PCB texts and schematic rectangles, wires, flags and attributes are not affected. 3.2.209: unchanged, modify too; the circle delete still works (#36). |
| Orphan attributes | Deleting a part or a net flag through the API leaves its attribute texts (designator, name, pin texts) on the page; their parent id is <part>-e<n>. Delete them explicitly. 3.2.209: no longer – a part's and a net flag's attributes go with it, none left after save and reopen. edakit keeps its sweep (schematic layout) as a cheap check for pages from before. |
| Page size | New pages are A4. DMT_Schematic.modifySchematicPageTitleBlock(page, {Width: {…, value}, Height: {…, value}}) plus the field Page Size. Standard sizes in 10-mil units: A4 1170 × 825, A3 1654 × 1170, A2 2339 × 1654, A1 3311 × 2339, A0 4681 × 3311. |
| Title block | modifySchematicPageTitleBlock(page, {field: {showTitle, showValue, value}}) – since 3.2.209 every item needs showTitle and showValue as booleans, else INVALID_TITLE_BLOCK_ITEM; edakit sends true for the shown fields, false for Width and Height. Shown: Company, Drawn, Reviewed, Version, Page Size; the big centre cell shows the project name, Page the page name (modifySchematicPageName). getSchematicPageInfo returns new values only after a while. |
| Sheet frame | The title block belongs to the frame, a component of type sheet (SCH_PrimitiveComponent.getAll("sheet")). Without it titleBlockData is empty. Create one with the system device "Drawing-Symbol_A4" (LIB_Device.search("Drawing-Symbol")) – it appears at once, but the answer never comes; use a short timeout and look. |
| Rectangles, texts | SCH_PrimitiveRectangle.create(left, top, width, height, radius, rot, colour, fill, line width, line type) – height goes towards −y, line type 1 = dashed. SCH_PrimitiveText.create(x, y, text, rot, colour, font, size, bold, italic, underline, alignMode) – \n for several lines; alignMode 3: (x, y) = bottom of the last line, 1: top left. |
| Opening a big page | A 120-part A1 page took up to 160 s until it was active. A timeout while opening does not mean it failed. |
9.4 PCB¶
| Topic | Behaviour |
|---|---|
| Units | mil, y up. Two fields come in 10 mil units: pour fills (PCB_PrimitivePoured … PourFills), and the hole of a pin from PCB_PrimitiveComponent.getAllPinsByPrimitiveId – a 1.1 mm hole is ["ROUND", 4.331, 4.331] beside its pad ["RECT", 66.9, 66.9, 0] in mil (3.2.206); the same pin's Hole in its state is in mil. Everything else in mil. |
| Netlist → PCB | PCB_Document.importChanges(uuid, true) opens the confirmation dialog anyway (force has no effect). Pure net changes without dialog: PCB_PrimitivePad.modify(padId, {net}) (pads of parts have their own ids from getAllPinsByPrimitiveId). 3.2.209: the handler reads only source and drops uuid and force; the call returns true while the dialog is open (#46). |
| Parts without dialog | PCB_PrimitiveComponent.create({libraryUuid: <project>, uuid: <device>}, layer, x, y, rot, lock) creates the part without designator link (e.g. BUZZER1, empty UniqueId). Then modify(id, {designator, uniqueId, otherProperty}). uniqueId = UniqueId of the same part in the schematic – that is the link. otherProperty replaces all properties, so pass the complete set incl. Channel ID (no fixed rule; take the next free $1I<n>). The properties must come from the schematic, not the library: if e.g. the Description differs, the DRC reports "Netlist Error – Import Changes" (it compares like the dialog). To swap a part, delete the old one first – its tracks stay. |
| The one click left | When a part was freshly placed in the schematic from the library, the DRC reports "Netlist Error – Import Changes" until the import view was opened once in the GUI (it shows "no changes"). importChanges() through the API, LIB_Device.get and reloading do not help. edakit tells it apart from a real difference: it compares schematic and PCB itself (pcb parts, pcb nets dry) – "EasyEDA waits for the import acknowledgement", exit 3 of route/silk (routing, 7.5). 3.2.209: the cause is the Channel ID. A part placed through the API has an empty Channel ID attribute (and no UniqueId yet); the import view gives it one ($1I49) and then reports the PCB part's other value. Written into the schematic part as well (SCH_PrimitiveComponent.modify with uniqueId and otherProperty["Channel ID"]), with the same value on the PCB part, the DRC is clean without the import view – edakit does that in pcb parts --write, and route/silk for parts linked before (TD-37, live: a resistor placed through the API, the old way the item, the new one none; an old one fixed by route drc, exit 0). The API reads no Channel ID of a schematic part back – getAll leaves it out –, so edakit writes it for every linked part; a DRC right after the writes still reported the item, after a reload of the PCB none. |
| Net classes | PCB_Drc.createNetClass(name, nets, {r,g,b,alpha} \| null) returns false as soon as one net is missing in the PCB; alpha is read as 0–255. The classes live in the net rules: getAllNetClasses reads the netClass entries of getNetRules (the nets are their sub), and createNetClass, addNetToNetClass, removeNetFromNetClass and deleteNetClass go through EasyEDA's own net class command (editor bundle pro-pcb/3.2.193…/js/pcb.js, pcb/extensionAPI/drc-createNetClass ff.). |
| DRC rule set | PCB_Drc.getCurrentRuleConfiguration() → {name, config}: name is the template the PCB's rules came from ("JLCPCB Capability(Two Layers Board)" when it never had another), config the rules of the PCB – categories Spacing, Physics, Plane, Expansion, in each kind one or more rules with unit ("mm") and isSetDefault. Safe Spacing is a lower triangle (row 13 kinds of object, column 12, tables {"1": {content}}), Track has minValue/defaultValue/maxValue per entry ("1"; "1" and "2" in class rules made in the GUI on a two-layer board), Via Size viaOuterdiameterMin … viaInnerdiameterDefault. The values lie 9 levels deep – return depth 12 needed. getNetRules() → per class and per net the rule name of each kind ("default" = the rule with isSetDefault), a class's nets under sub. Read on 3.2.206 from a real project (tests/fixtures/easyeda/drc_rules_3.2.206.json). Signatures: pro-api/0.3.50…/api-types.d.ts of the client, class PCB_Drc. Writing: overwriteCurrentRuleConfiguration(config) takes the inner config, overwriteNetRules(rules) the whole list; the editor puts either into the PCB's rules without any check and returns true whenever the PCB tab counts as active (bundle: pcb/extensionAPI/drc-overwriteCurrentRuleConfiguration, -overwriteNetRules) – only a read-back and a DRC show what came of it. Live (step 2.2): what is written holds after save and reload and the DRC uses it at once; the rules are the PCB's (a second PCB keeps its own); a Track rule with the entry "1" alone covers every copper layer; the moved nets of a new class keep "default" until the net rules are written. The first overwrite renames the PCB's configuration to the client's "Custom Config" ("自定义配置") and saves that name in the client's preferences (web.db), so it appears in every project's list; no call puts a PCB back on a named configuration, and deleteRuleConfiguration answers true while a PCB uses it and keeps the entry. saveRuleConfiguration, setAsDefaultRuleConfiguration and deleteRuleConfiguration act on the client's named configurations, not on the PCB. edakit reads it for GEO.drc with [routing] drc_rules (routing, 7.5). |
| Auto-layout | PCB_Document.autoLayout places only unlocked parts, only on TOP, knows nothing about which capacitor belongs to which IC, and keeps running after the bridge timeout. 3.2.209, from the docs: autoLayout() takes no parameter. |
| Autorouter | PCB_Document.autoRouting keeps its result only if the whole run succeeds; on abort or error it discards everything (API docs; observed: 1773 lines → 223). Fixed 900 s limit, runs past the bridge timeout, sometimes does not start, left nets open, routes nothing on nets that are partly routed. Use Freerouting. |
| DSN/SES | PCB_ManufactureData.getDsnFile returned null (tab "inactive"); importAutoRouteSesFile needs a File object the bridge cannot pass. edakit writes the DSN itself and creates tracks and vias from the SES. |
| Tracks, vias, texts | PCB_PrimitiveLine.create(net, layer, x1, y1, x2, y2, width, lock), PCB_PrimitiveVia.create(net, x, y, drill, diameter, 0, "", null, false), PCB_PrimitiveString.create(layer, x, y, text, font, size, line width, align, rot, invert, expand, mirror, lock) – all in mil. |
| Creating tracks | Pieces shorter than ~0.5 mil are dropped; straight consecutive pieces of a net (kink up to ~0.3 mil) are merged into one. Counting after creation is no check – compare geometrically. Track to track connects only through ends that coincide to ~0.01 mil (0.02 mil off = "disconnected"); at pads and vias it is enough that the end lies inside. Pieces completely inside a via are dropped. |
| Deleting tracks | PCB_Document.clearRouting runs into a dialog timeout. Delete with PCB_PrimitiveLine/PCB_PrimitiveVia.delete and id lists – then count again: deleting sometimes needs a second pass, and old tracks reappeared after a reload. 3.2.209: clearRouting("all") does not answer within 120 s, no dialog, nothing cleared (#38). |
| DRC after API changes | Reported false "Connection Error"s on correct tracks as long as the PCB was not saved and reloaded (320 errors, minutes later still; reloaded: 0). Save, DMT_EditorControl.closeDocument(tabId), openDocument(pcbUuid). 3.2.209: not seen – a track deleted through the API gives a failing DRC at once, created again a passing one, without save and reload; on a PCB never reloaded since EasyEDA's start, pours refilled and tooling holes replaced, the DRC reports 0. edakit reloads only when the DRC reports Connection Errors and runs it once more (eda.drc_reloading). |
| DRC result | PCB_Drc.check(true, false, true) with details always returns a list ([] = no findings); null means it did not run. |
| Pours | PCB_PrimitivePour.create(net, layer, {$polygon}, "solid", preserveIslands, name, priority, line width). A $complexPolygon with a hole is taken only as its outer contour, and filling fails then. Fill with easyeda_pcb_rebuild_copper (per net); its status readback-mismatch is harmless (it compares only the returned id). Whether it filled: PCB_PrimitivePoured.get(<pourId>) → PourFills. 3.2.209, from the docs: createComplexPolygon shows separate pieces, not holes; a hole in a pour is a region with NO_POURS (EPCB_PrimitiveRegionRuleType 7). The docs' example of rebuildCopperRegion warns of an internal error on pours made through the API. EasyEDA's beta rebuildCopperRegion answers with another pour of the net when that net's copper is already poured; until 1.6.0 a call for a whole net (its second pour) came back readback-mismatch, and from then on the bridge refuses every rebuild until EasyEDA restarts ("A previous native PCB copper rebuild ended without complete verification"). Since 1.7.0 the bridge verifies a net's second fresh pour against the copper the first one left (M-10); edakit creates its pours anew before each fill and fills a net's pours in one call. On 3.2.209 (live on desk-led, easyeda-mcp-pro 1.11.0): once pads (tooling holes), vias or tracks were created or deleted through the API in the session, rebuildCopperRegion returns no copper for every pour – no-copper, or readback-mismatch on a pour already filled – until the PCB is loaded again (save, close its tab, open it); a restart is not needed, and two fills in a row without such a change both pass. edakit saves and reloads the PCB before each fill (eda.reload_pcb, M-13). no-copper with verified: true does not lock the bridge; it is also EasyEDA's answer for a pour whose net has no pad, via or track on its layer, which edakit names as the board's. A second fill of the same pour still mismatches – not edakit's case. edakit (E-13, live): the pour follows the outline, and a NO_POURS region on all layers (PCB_PrimitiveRegion.create(12, polygon, [7], name)) around every mounting and tooling hole keeps them free – no notch to the edge any more. EasyEDA keeps no region name (RegionName null); edakit remembers the ids (<artifacts>/pcb/<board>_keep_regions.json) and also takes a NO_POURS region centred on a hole as its own. |
| Free pads | PCB_PrimitivePad.create(12, "TL1", x, y, 0, ["ELLIPSE", d, d], "", ["ROUND", d], 0, 0, 0, false, 0, [], {topSolderMask, bottomSolderMask, topPasteMask, bottomPasteMask}, null, true) creates a pad without part; non-plated it lands in Drill_NPTH_Through.DRL, without a copper ring when pad and hole have the same size – a JLCPCB tooling hole. While such a pad is in the PCB, easyeda_pcb_rebuild_copper fails ("Cannot read properties of undefined (reading 'length')"), whatever its settings; DRC and export work. So take tooling holes out before filling and put them back after. 3.2.209: the fill works with the non-plated tooling holes TL1 and TL2 on the board; a pad outside the outline made it return no copper. edakit leaves them on the board while the pours fill (E-13). |
| Designators | Attributes (PCB_PrimitiveAttribute, key Designator). modify(id, {valueVisible, x, y, rotation, alignMode: 5, fontSize}) works on locked parts too; alignMode 5 = centre at x/y. Stroke font default: 0.5–0.6 × height per character. Size of any primitive: PCB_Primitive.getPrimitivesBBox. |
| Bottom silkscreen | EasyEDA mirrors texts on the bottom silk layer itself (create with mirror = false, with true they read mirrored from outside). It does not mirror graphics (fills, lines) – mirror those yourself. |
| Footprint geometry | Turning a part to 0° on TOP and reading pads relative to its origin gives the library geometry; on the bottom side EasyEDA mirrors local y, then rotates. LIB_Footprint.getDocumentSource, the documented reader of a footprint's source, hung for minutes; 3.2.209: it never answers – the client has no handler for it (#50). |
| Footprints in the project | Editing: LIB_Footprint.openInEditor(fp, <project UUID>) (with "project" it fails), then PCB_PrimitivePad.modify/delete in the editor, PCB_Document.save, close the tab. Placed parts keep their embedded copy until deleted and recreated. The copies of a placed system part are found on the schematic: SCH_PrimitiveComponent.getAll("part") → Symbol.uuid, Footprint.uuid (the Christmas bell's tdisplay_device.py); a device created through the API cannot be placed in the local client ("Device details data does not exist"), the copy of a system part can. edakit part build rebuilds a copy from the parts entry's footprint data this way (own parts, 4.5): pads deleted and created (PCB_PrimitivePad.create(12, number, x, y, rot, ["RECT", w, h, 0] \| ["ELLIPSE"\|"OVAL", w, h], "", ["ROUND", d] \| ["SLOT", d, l], 0, 0, hole rotation, plated)), the print on layers 3, 48, 49 and 50 deleted and drawn (PCB_PrimitivePolyline.create("", layer, {$polygon}, width, false), PCB_PrimitiveString.create), the symbol's pins created anew (SCH_PrimitivePin.modify is not saved – the bell). Live (step 3.6): the pads come back as built (holes in mil); the parts of the schematic keep the old symbol until placed anew (schematic create, schematic layout), and only then PCB_PrimitiveComponent.create places the rebuilt copy – before that it failed with "Cannot convert undefined or null to object" for the device and for the footprint alone, the cause not found. LIB_Footprint.copy creates a footprint without device, LIB_Device.copy/create give unusable devices. Changing pins through the graph (e.g. swapping which net goes to which pad) was the faster way than repairing a library footprint. 3.2.209: SCH_PrimitivePin.modify in the symbol editor is saved – part build modifies a pin of the same number in place, creates a new one, deletes one the box no longer has (E-11); LIB_Device.copy throws (the bridge passes only "[object Object]"); updating placed parts to an edited footprint has no call (#49). |
| View | DMT_EditorControl.zoomTo(x, y, zoom) centres at (x, y) at zoom/100 px per unit; the bottom in its return value is wrong. Canvas images come as an MCP image block. |
9.5 Gerber export (what edakit reads)¶
- Files:
Gerber_TopLayer.GTL,Gerber_BottomLayer.GBL, silkGTO/GBO, maskGTS/GBS, outlineGKO, drillsDrill_PTH_Through.DRL,Drill_PTH_Through_Via.DRL,Drill_NPTH_Through.DRL, plusFlyingProbeTesting.jsonwith every pad (position, size, layer, name<designator>_<pin>). - No net attributes (
%TO.N) in the Gerber files; FlyingProbeTesting.json renames some nets (NET_3). Take the net of each pad from the graph. - Pads are always apertures (flashes), never regions. Pours are regions, and EasyEDA traces the edge of every pour as a line on top.
- The mask layers use the aperture macro
RoundRect. - Gerber coordinates are EasyEDA's coordinates in mm.