Adding a Printer Adapter
PrintStudio’s printer adapters live in packages/integrations/adapters/. Each adapter implements a common PrinterAdapter interface, so the rest of the system doesn’t need to know which protocol a printer uses.
The PrinterAdapter Interface
Section titled “The PrinterAdapter Interface”interface PrinterAdapter { // Connection connect(): Promise<void>; disconnect(): Promise<void>; isConnected(): boolean;
// Status getStatus(): Promise<PrinterStatus>; getTemperatures(): Promise<Temperatures>; getPrintProgress(): Promise<PrintProgress>;
// Job control uploadFile(filename: string, data: Buffer): Promise<void>; startPrint(filename: string): Promise<void>; pausePrint(): Promise<void>; resumePrint(): Promise<void>; cancelPrint(): Promise<void>;
// Emergency emergencyStop(): Promise<void>;}Step 1 — Create the Adapter
Section titled “Step 1 — Create the Adapter”Create a directory for your adapter:
mkdir -p packages/integrations/src/adapters/my-printertouch packages/integrations/src/adapters/my-printer/index.tstouch packages/integrations/src/adapters/my-printer/client.tstouch packages/integrations/src/adapters/my-printer/types.tsclient.ts — Raw protocol client
Section titled “client.ts — Raw protocol client”export class MyPrinterClient { constructor( private readonly baseUrl: string, private readonly apiKey?: string ) {}
async getStatus(): Promise<MyPrinterStatus> { const res = await fetch(`${this.baseUrl}/status`, { headers: this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}, }); if (!res.ok) throw new Error(`MyPrinter API error: ${res.status}`); return res.json() as Promise<MyPrinterStatus>; }
// ... implement protocol-specific methods}index.ts — Adapter that implements PrinterAdapter
Section titled “index.ts — Adapter that implements PrinterAdapter”import type { PrinterAdapter, PrinterStatus, Temperatures } from "../../types.js";import { MyPrinterClient } from "./client.js";
export class MyPrinterAdapter implements PrinterAdapter { private client: MyPrinterClient; private connected = false;
constructor(config: { baseUrl: string; apiKey?: string }) { this.client = new MyPrinterClient(config.baseUrl, config.apiKey); }
async connect(): Promise<void> { const status = await this.client.getStatus(); if (!status.online) throw new Error("Printer not reachable"); this.connected = true; }
async disconnect(): Promise<void> { this.connected = false; }
isConnected(): boolean { return this.connected; }
async getStatus(): Promise<PrinterStatus> { const raw = await this.client.getStatus(); // Map printer-specific status to PrintStudio's unified status return { state: raw.printing ? "printing" : raw.idle ? "idle" : "offline", progress: raw.progress ?? 0, }; }
async getTemperatures(): Promise<Temperatures> { // Implement based on your printer's API throw new Error("Not implemented"); }
// ... implement remaining methods}Step 2 — Register in PrinterManager
Section titled “Step 2 — Register in PrinterManager”import { MyPrinterAdapter } from "./adapters/my-printer/index.js";
// In the registerPrinter method, add a case:case "my-printer": return new MyPrinterAdapter({ baseUrl: config.baseUrl, apiKey: config.apiKey, });Step 3 — Add to IntegrationHub (optional)
Section titled “Step 3 — Add to IntegrationHub (optional)”If your adapter needs hub-level configuration:
export class IntegrationHub { myPrinter?: MyPrinterAdapter;
constructor(config: IntegrationHubConfig) { if (config.myPrinter) { this.myPrinter = new MyPrinterAdapter(config.myPrinter); } }}Step 4 — Write Tests
Section titled “Step 4 — Write Tests”import { describe, it, expect, mock } from "bun:test";import { MyPrinterClient } from "./client.js";
describe("MyPrinterClient", () => { it("returns printer status", async () => { const client = new MyPrinterClient("http://localhost:1234"); // Mock fetch or use a test server const status = await client.getStatus(); expect(status).toBeDefined(); });});Step 5 — Export from Package
Section titled “Step 5 — Export from Package”Add your adapter to the package exports in packages/integrations/package.json:
{ "exports": { "./adapters/my-printer": "./src/adapters/my-printer/index.ts" }}Step 6 — Register via API
Section titled “Step 6 — Register via API”Test your adapter by registering a printer:
curl -X POST http://localhost:8787/api/printers \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -d '{ "name": "My Printer #1", "type": "my-printer", "machineType": "fdm_standard", "baseUrl": "http://192.168.1.200:1234" }'Existing Adapters for Reference
Section titled “Existing Adapters for Reference”| Adapter | Protocol | Complexity |
|---|---|---|
moonraker | REST (HTTP) | Medium — good starting point |
octoprint | REST (HTTP) | Simple |
bambu | MQTT | Complex — async events |
The Moonraker adapter is the recommended reference implementation. Start there and adapt the protocol-specific parts.