MCP 3D Printer Server
by DMontgomery40
Verified
- node_modules
- bambu-js
- src
- classes
import EventEmitter from "node:events";
import mqtt from "mqtt";
const MQTT_USERNAME = "bblp";
/**
* A class for interfacing with a Bambu Lab printers over MQTT.
* @emits update - Emitted when the printer's state is updated.
* @emits connect - Emitted when the printer is connected.
* @emits disconnect - Emitted when the printer is disconnected.
*/
export default class BambuMQTT extends EventEmitter {
host: string;
accessCode: string;
serial: string;
private client: mqtt.MqttClient;
/**
* Create a new BambuMQTT instance.
* @param host - The host of the printer.
* @param accessCode - The access code for the printer.
* @param serial - The serial number of the printer.
*/
constructor(host: string, accessCode: string, serial: string) {
super();
this.host = host;
this.accessCode = accessCode;
this.serial = serial;
}
/**
* Connect to the printer.
*/
async connect() {
this.client = mqtt.connect(`mqtt://${this.host}:8883`, {
username: MQTT_USERNAME,
password: this.accessCode,
clientId: MQTT_USERNAME,
protocol: "mqtts",
rejectUnauthorized: false,
reconnectPeriod: 5000,
});
this.client.on("connect", this.onConnect.bind(this));
this.client.on("close", this.onClose.bind(this));
this.client.on("message", this.onMessage.bind(this));
this.client.on("error", async (error) => {
this.emit("error", new Error("Client error"));
await this.disconnect();
});
this.client.stream.on("error", async (error) => {
this.emit("error", new Error("Stream error"));
await this.disconnect();
});
}
/**
* Disconnect from the printer.
*/
async disconnect() {
this.client.end();
this.client.emit("close");
this.client.removeAllListeners();
this.emit("disconnect");
}
/**
* Send a request to the device.
* @param payload - The payload to send to the device.
*/
sendRequest(payload: any) {
this.client.publish(
`device/${this.serial}/request`,
JSON.stringify(payload),
);
}
/**
* Handle the connection event.
*/
private async onConnect() {
// Subscribe to the printer
this.client.subscribe(`device/${this.serial}/report`);
// Request the printer's complete state
this.sendRequest({ pushing: { sequence_id: "0", command: "pushall" } });
this.emit("connect");
}
/**
* Handle the close event.
*/
private onClose() {
this.emit("disconnect");
}
/**
* Handle an incoming message.
* @param topic - The topic the message was sent to.
* @param message - The message payload.
*/
private onMessage(topic: string, message: Buffer) {
const payload = JSON.parse(message.toString());
if (topic === `device/${this.serial}/report`) {
if (payload.print) {
if (payload.print.command === "push_status") {
// Remove message metadata
let state = {
...payload.print,
command: undefined,
msg: undefined,
sequence_id: undefined,
};
// Emit the update event
this.emit("update", state);
}
}
}
}
/**
* Get the current connection status.
*/
get isConnected() {
return this.client.connected;
}
}