A node.js library for connecting to and receiving data from Bambu Lab printers through their MQTT servers.
npm install @hiv3d/bambu-node> [!CAUTION]
> 🚧 This library is still in the making. PRs and other feature requests are welcome.
A node.js library for connecting to and receiving data from Bambu Lab printers through
their MQTT servers.
- Every command & response field is documented & typed.
- Easily (and safely\*) construct commands & manage responses.
- Full async support! client#executeCommand waits until the command completion is
verified by the printer.
Make sure you have the following installed:
- Node.js
- NPM
- TypeScript
> [!CAUTION]
> TypeScript is highly recommended for this package due to the type safety it provides.
> This is especially important in use cases like this project where the library
> communicates with external hardware which can very well come with property damage. And
> even with TypeScript, I am not liable for any such damages as stated in the
> license.
``bash`
npm install bambu-node
#### Sequence ID
The sequence_id is a critical component of the Bambu Lab printer communication protocol. It ensures reliable, ordered, and secure command processing between the client and printer.
##### How It Works
- Each command sent to the printer includes a unique sequence_id
- Valid sequence_ids must be between 20000 and 30000
- The sequence_id must be incremented for each new command
- The printer returns responses with the same sequence_id as the original command
##### Why It's Critical
1. Command Validation
- The sequence_id range acts as a security measure
- Only commands with valid sequence_ids are processed
- Helps prevent unauthorized command injection
2. Command-Response Matching
- Responses include the original command's sequence_id
- Allows matching responses to their originating commands
- Essential for asynchronous command processing
3. Error Handling
- Error responses are matched to commands via sequence_id
- Enables proper error attribution and handling
- Critical for temperature and safety-related commands
4. State Management
- Maintains proper command ordering
- Prevents command duplication
- Ensures reliable command acknowledgment
##### Implementation Requirements
- Always increment sequence_id for each new command
- Never reuse sequence_ids within a session
- Validate sequence_ids in responses match sent commands
- Handle sequence_id wraparound when reaching the upper limit
##### Consequences of Improper Implementation
Failing to properly implement sequence_id management can result in:
- Commands being ignored or rejected
- Incorrect error attribution
- Mixed up command responses
- Failed command acknowledgments
- Compromised safety features
##### Library Implementation
The library provides a sequenceIdManager utility that handles sequence IDs according to the protocol specification:
`typescript
import { getSequenceId, isValidSequenceId, START_SEQ_ID, END_SEQ_ID } from './utils/sequenceIdManager';
// Get next sequence ID (automatically handles wraparound)
const nextId = getSequenceId(); // Returns number between 20000-30000
// Validate incoming sequence IDs
const isValid = isValidSequenceId(nextId); // Returns true if within valid range
// Example usage in commands
async function sendCommand(command: any) {
// Automatically assign next valid sequence ID
command.sequence_id = getSequenceId();
// Send command and validate response sequence_id matches
const response = await sendToDevice(command);
if (!isValidSequenceId(response.sequence_id)) {
throw new Error('Invalid sequence ID in response');
}
if (response.sequence_id !== command.sequence_id) {
throw new Error('Response sequence ID mismatch');
}
return response;
}
`
The sequence ID management is handled automatically by the library's internal command processing, so you typically don't need to manage it directly when using the public API.
`typescript
import { BambuClient, Fan, UpdateFanCommand } from "bambu-node"
// define a printer connection
const client = new BambuClient({
host: "your_printers_ip",
accessToken: "your_printers_access_token",
serialNumber: "your_printers_sn",
})
// more about the available events below
client.on("message", (topic, key, data) => {
console.log(New ${key} message!, data)
})
client.on("printer:statusUpdate", (oldStatus, newStatus) => {
console.log(The printer's status has changed from ${oldStatus} to ${newStatus}!)
})
// connect to the printer
await client.connect()
// update the speed of the auxiliary fan to 100%
await client.executeCommand(new UpdateFanCommand({ fan: Fan.AUXILIARY_FAN, speed: 100 }))
// we don't want to do anything else => we close the connection
// (can be kept open indefinitely if needed)
await client.disconnect()
`
#### Legend
Unnamed things inside classes: Other classes that extend that class.
Every method, command and response is documented in JSDoc, so only events & utility
classes are documented here.
- Bambu Node
- Class: BambuClient
- Method: BambuClient.connect()BambuClient.disconnect()
- Method: BambuClient.subscribe(topic)
- Method: BambuClient.executeCommand(command)
- Method: message
- Event: rawMessage
- Event: client:connect
- Event: client:disconnect
- Event: printer:dataUpdate
- Event: printer:statusUpdate
- Event: job:update
- Event: job:start
- Event: job:pause
- Event: job:offlineRecovery
- Event: job:unpause
- Event: job:finish
- Event: Job
- Class: Job.update(data)
- Method: Job.data
- Getter: AbstractCommand
- Class: GCodeCommand
- Class: GCodeFileCommand
- GCodeLineCommand
- GetVersionCommand
- PushAllCommand
- UpdateFanCommand
- UpdateLightCommand
- UpdateSpeedCommand
- UpdateStateCommand
- UpdateTempCommand
- InfoMessageCommand
- _Command Responses_
- info
- Class: GetVersionResponse
- McPrintMessageCommand
- mcPrint
- Class: PushInfoResponse
- PrintMessageCommand
- print
- Class: GCodeFileResponse
- GCodeLineResponse
- ProjectFileResponse
- PushAllResponse
- PushStatusResponse
- UpdateFanResponse
- UpdateLightResponse
- UpdateSpeedResponse
- UpdateStateResponse
- UpdateTempResponse
-
Responsible for managing the connection and messages to/from the printer.
#### Events
##### rawMessage
Triggered whenever a new message is received from the MQTT broker.
#### message
Triggered whenever a new known message is received from the MQTT broker. It's
already parsed and sent using its type.
#### client:connect
Triggered whenever the client connects to the printer. This will also trigger on a
reconnect.
#### client:disconnect
Triggered whenever the client disconnects from the printer. This can be on purpose using
the client#disconnect method or when the printer itself goes offline.
#### client:error
Triggered whenever the internal MQTT client encounters an error.
Examples include:
- Unresolvable host provided
- Incorrect credentials provided
- Unexpected responses
#### printer:dataUpdate
Triggered whenever new data is received from the printer and is merged into the data class
field.
#### printer:statusUpdate
Triggered whenever the printer's status changes to a new status.
#### job:update
Triggered whenever the current Job's data gets updated.
#### job:start
Triggered whenever a new printing job starts.
#### job:pause
Triggered whenever the current print job is paused.
#### job:offlineRecovery
Triggered whenever the current print job was recovered after the printer came back online
from an offline state.
#### job:unpause
Triggered whenever the current print job is resumed.
#### job:finish
Triggered whenever the current print job finishes.
Possible reasons:
- SUCCESS: Triggered whenever the current print job finishes without errors.FAILED
- : Triggered whenever the current print job finishes without errors.UNEXPECTED
- : Triggered whenever the current print job finishes unexpectedly. This is
only included as a proof of concept and is 99% bound to never happen.
Responsible for managing the data about the current print job. It collects historical
data, error codes, etc. It is included in every event starting with job:`.
Pull requests are welcome. For major changes, please open an issue first to discuss what
you would like to change.