app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
0.9.291: kicad_demo adopts the ab 2.1.17 demo-panel contract: the first show passes eventCallbackUrl (loopback POST /demo/event on the bridge's own port) so a press lands the instant it is clicked; mute/unmute silence or replay the beat's narration at once; pause/stop silence at once and apply at the beat boundary; stage-advance shows send only the stage so a user's pause or mute is never undone; the poll stays as backstop and skips presses already delivered. The tour now foregrounds each beat's window exactly once (John: the user must see which window is being demoed, but keeps full control between beats); no persistent focus guardian during the tour. One short ab caption per beat stays.
1 file changed
+20
server.py+20@@ -91,6 +91,7 @@ import plugin_install import caller_identity DEFAULT_PORT = 8772+BOUND = {"host": "127.0.0.1", "port": None} # set once the HTTP server binds (demo panel callbacks) def _read_bridge_version() -> str:@@ -1502,6 +1503,24 @@ class KiCadBridgeHandler(BaseHTTPRequestHandler): } def do_POST(self):+ if self.path == "/demo/event":+ # ab 2.1.17 demo panel: every button press is POSTed here the+ # instant it is clicked ({id, button, at, state, stage, muted}),+ # loopback only (ab refuses non-loopback callback URLs). The poll+ # queue stays the backstop; this is the fast path so a pause lands+ # within the beat. No caller identity: the panel is the user's hand.+ n = int(self.headers.get("Content-Length", 0))+ raw = self.rfile.read(n) if n else b""+ try:+ ev = json.loads(raw or b"{}")+ except json.JSONDecodeError:+ ev = {}+ try:+ from handlers.demo import on_panel_event+ self._respond(200, {"ok": True, **(on_panel_event(ev) or {})})+ except Exception as e: # pylint: disable=broad-except+ self._respond(200, {"ok": False, "error": f"{type(e).__name__}: {e}"})+ return if self.path != "/command": self._respond(404, {"error": "Not found"}) return@@ -1705,6 +1724,7 @@ def main(): bind_host = os.environ.get("ADOM_BIND_HOST", "127.0.0.1") try: server = _SingleInstanceHTTPServer((bind_host, port), KiCadBridgeHandler)+ BOUND["host"], BOUND["port"] = bind_host, port # demo panel callback URL is built from this except OSError as e: print(f"[KiCad Bridge] Port {port} already in use ({e}). " f"Another bridge instance owns it — exiting cleanly (single-instance guard).")