First Commit

This commit is contained in:
Carsten Graf
2026-03-05 14:52:36 +01:00
commit d5353b3c2b
24 changed files with 3893 additions and 0 deletions

133
src/octoprint-client.ts Normal file
View File

@@ -0,0 +1,133 @@
// src/octoprint-client.ts
// OctoPrint REST API client
export interface OctoPrintSettings {
host: string; // e.g. "http://octopi.local" or "http://192.168.1.100"
port: string; // e.g. "80" or "5000"
apiKey: string; // OctoPrint API key
}
export interface PrinterState {
state: {
text: string;
flags: {
operational: boolean;
paused: boolean;
printing: boolean;
pausing: boolean;
cancelling: boolean;
sdReady: boolean;
error: boolean;
ready: boolean;
closedOrError: boolean;
};
};
temperature?: {
tool0?: { actual: number; target: number };
bed?: { actual: number; target: number };
};
}
export interface JobState {
job: {
file: { name: string | null };
estimatedPrintTime: number | null;
};
progress: {
completion: number | null;
printTimeLeft: number | null;
printTime: number | null;
};
state: string;
}
export class OctoPrintClient {
private baseUrl: string;
private apiKey: string;
constructor(settings: OctoPrintSettings) {
const port = settings.port ? `:${settings.port}` : "";
this.baseUrl = `${settings.host}${port}/api`;
this.apiKey = settings.apiKey;
}
private get headers(): Record<string, string> {
return {
"X-Api-Key": this.apiKey,
"Content-Type": "application/json",
};
}
async getPrinterState(): Promise<PrinterState> {
const res = await fetch(`${this.baseUrl}/printer`, {
headers: this.headers,
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json() as Promise<PrinterState>;
}
async getJobState(): Promise<JobState> {
const res = await fetch(`${this.baseUrl}/job`, {
headers: this.headers,
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
return res.json() as Promise<JobState>;
}
async pausePrint(): Promise<void> {
await fetch(`${this.baseUrl}/job`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ command: "pause", action: "toggle" }),
});
}
async cancelPrint(): Promise<void> {
await fetch(`${this.baseUrl}/job`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ command: "cancel" }),
});
}
async homeAxes(axes: string[] = ["x", "y", "z"]): Promise<void> {
await fetch(`${this.baseUrl}/printer/printhead`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ command: "home", axes }),
});
}
async setTemperature(tool: "tool0" | "bed", target: number): Promise<void> {
if (tool === "bed") {
await fetch(`${this.baseUrl}/printer/bed`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ command: "target", target }),
});
} else {
await fetch(`${this.baseUrl}/printer/tool`, {
method: "POST",
headers: this.headers,
body: JSON.stringify({ command: "target", targets: { [tool]: target } }),
});
}
}
async testConnection(): Promise<boolean> {
try {
const res = await fetch(`${this.baseUrl}/version`, { headers: this.headers });
return res.ok;
} catch {
return false;
}
}
}
export function formatTime(seconds: number | null): string {
if (seconds === null || seconds === undefined) return "--:--";
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
if (h > 0) return `${h}h ${m}m`;
return `${m}m`;
}