MQTT Remote Access Proxy¶
OctoEverywhere's Bambu Connect is our plugin for Bambu Lab 3D printers.
Bambu Lab 3D printers work differently from OctoPrint, Klipper, and Prusa Connect 3D printers. They rely on a protocol called MQTT to command and control the printer.
MQTT is a lightweight protocol on top of TCP, which makes remote access tricky. However, we developed a WebSocket proxy for MQTT to allow Bambu Lab app developers to use OctoEverywhere's App Connections remote access.
Our MQTT proxy can be almost like an MQTT tunnel through a web socket. We designed the messages to be very similar to the MQTT messages, so only minor changes have to be made to swap our WebSocket proxy for an actual MQTT implementation.
Connection & Authentication¶
Websocket Endpoint¶
The OctoEverywhere MQTT Websocket Proxy can be used from any App Connection URL or Shared Connection URL.
wss://app-<id>.octoeverywhere.com/octoeverywhere-command-api/proxy/mqtt
For the WebSocket authentication to OctoEverywhere's servers, use the same auth headers that you would use for other App Connection HTTP or WebSocket requests.
When your client makes a WebSocket connection to the OctoEverywhere endpoint, the proxy MQTT connection will automatically be started, connected, and ready to use. If the printer's MQTT connection fails, the WebSocket will close with one of the OctoEverywhere common error codes.
Bambu Lab MQTT Authentication¶
The Bambu Lab 3D printer's MQTT authentication is handled for you! The OctoEverywhere plugin will automatically use the same Bambu Lab serial number and access code that the user set for the OctoEverywhere plugin connection.
WebSocket MQTT Protocol¶
Our WebSocket proxy protocol attempts to mirror MQTTs protocol as closely as possible. Thus, concepts like subscribing and publishing work the same way.
Message Flow¶
Here's an example of what the MQTT websocket proxy messages might look like when connecting to a Bambu Lab 3D printer.
Your App (Websocket MQTT Proxy) Bambu Lab 3D Printer MQTT Server
subscribe-> subscribe-> subscribe->
<-subscribe_ack <-subscribe_ack
...
<-on_subscribe <-on_subscribe <-on_subscribe
...
<-on_message <-on_message <-on_message
<-on_message <-on_message <-on_message
...
publish-> publish-> publish->
<-publish_ack <-publish_ack
...
<-on_message <-on_message <-on_message
...
The subscribe
message can have an ID your client randomly generates which will then be paired with the subscribe_ack
, allowing you to match the subscribe_ack
and subscribe_ack
messages. The subscribe_ack
will include the MQTT MID (message id). When the MQTT server sends back the on_subscribe
event, it will also include a MQTT MID, thus you are able to link each subscribe
request message with the resulting on_subscribe
event.
After your app is subscribed to a topic, the server will start sending on_message
messages whenever a topic update occurs. For Bambu Lab 3D printers, these messages include printer-state changes.
If you want to send a command, your app sends the publish
request message, which the MQTT Websocket Proxy will give you as the end result of using publish_ack
. The publish_ack
can be used to verify the publish message was forwarded successfully.
Message Concepts¶
As you can see in the example above, there are two message concepts for our WebSocket proxy.
-
Remote Function Calls Style Messages
- A "remote function call" (RPC) type message where you send a request and get an ack response back:
subscribe
->subscribe_ack
unsubscribe
->unsubscribe_ack
publish
->publish_ack
- A "remote function call" (RPC) type message where you send a request and get an ack response back:
-
Event Style Messages
- These are messages from the MQTT protocol, which the server sends as responses to function calls and/or streaming messages.
on_message
on_subscribe
on_unsubscribe
- These are messages from the MQTT protocol, which the server sends as responses to function calls and/or streaming messages.
RPC Style Messages¶
Subscribe¶
Here's an example of a subscribe
request message and the subscribe_ack
response.
{
"Type": "subscribe",
"Topic": "device/serial_number/report",
"Id": 1337,
"NoAck": false
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the action: subscribe . |
Topic | string | The MQTT topic to subscribe to. |
Id | int | Optional - A client created random int that will be repeated back to match the subscribe_ack response. |
NoAck | bool | Optional - If set to true, no subscribe_ack response will be sent. |
{
"Type": "subscribe_ack",
"AckResult": 0,
"MqttMessageId": 222,
"Id": 1337,
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the request ack: subscribe_ack . |
AckResult | int | The MQTT error code of the action. 0 indicates success, all other values are errors. |
MqttMessageId | int | The MQTT MID (Message Id) for the subscribe request. |
Id | int | Optional - If a random Id was sent in the subscribe request, the same Id will be returned here for matching. |
Unsubscribe¶
Here's an example unsubscribe
request message and the unsubscribe_ack
response.
{
"Type": "unsubscribe",
"Topic": "device/serial_number/report",
"Id": 2000,
"NoAck": false
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the action: subscribe . |
Topic | string | The MQTT topic to subscribe to. |
Id | int | Optional - A client created random int that will be repeated back to match the subscribe_ack response. |
NoAck | bool | Optional - If set to true, no unsubscribe_ack response will be sent. |
{
"Type": "unsubscribe_ack",
"AckResult": 0,
"MqttMessageId": 223,
"Id": 2000,
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the request ack: unsubscribe_ack . |
AckResult | int | The MQTT error code of the action. 0 indicates success, all other values are errors. |
MqttMessageId | int | The MQTT MID (Message Id) for the subscribe request. |
Id | int | Optional - If a random Id was sent in the unsubscribe request, the same Id will be returned here for matching. |
Publish¶
Here's an example publish
request message and the publish_ack
response.
{
"Type": "publish",
"Topic": "device/serial_number/report",
"Payload": "base64 encoded data",
"Id": 5000,
"NoAck": false
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the action: publish . |
Topic | string | The MQTT topic to publish to. |
Payload | string | Any binary data base64 encoded as a string. (usually a json string) |
Id | int | Optional - A client created random int that will be repeated back to match the subscribe_ack response. |
NoAck | bool | Optional - If set to true, no unsubscribe_ack response will be sent. |
{
"Type": "publish_ack",
"AckResult": 0,
"MqttMessageId": 224,
"Id": 5000,
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the request ack: publish_ack . |
AckResult | int | The MQTT error code of the action. 0 indicates success, all other values are errors. |
MqttMessageId | int | The MQTT MID (Message Id) for the subscribe request. |
Id | int | Optional - If a random Id was sent in the publish request, the same Id will be returned here for matching. |
Event Messages¶
OnMessage¶
Here's an example on_message
event message sent from the MQTT server. These messages are sent as updates once a topic has been subscribed to.
{
"Type": "on_message",
"Payload": "base64 encoded data",
"MqttMessageId": 255,
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the action: on_message . |
Payload | string | Any binary data base64 encoded as a string. (usually a json string) |
MqttMessageId | int | The MQTT MID (Message Id) from the MQTT server. |
OnSubscribe¶
Here's an example on_subscribe
event message sent from the MQTT server. This is sent by the MQTT server in response to a subscribe
request.
{
"Type": "on_subscribe",
"ReasonCodeList": [0, ...],
"MqttMessageId": 255,
"Id": 5000,
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the action: on_message . |
ReasonCodeList | list [int] | A list of MQTT version 5.0 reason codes. Code 0 is success, all others are failures. |
MqttMessageId | int | The MQTT MID (Message Id) from the MQTT server. |
Id | int | Optional - If a random Id was sent in the subscribe request, the same Id will be returned here for matching. |
OnUnsubscribe¶
Here's an example on_unsubscribe
event message sent from the MQTT server. This is sent by the MQTT server in response to a unsubscribe
request.
{
"Type": "on_unsubscribe",
"ReasonCodeList": [0, ...],
"MqttMessageId": 255,
"Id": 5000,
}
Parameters
Name | Type | Description |
---|---|---|
Type | string | Must be the action: on_unsubscribe . |
ReasonCodeList | list [int] | A list of MQTT version 5.0 reason codes. Code 0 is success, all others are failures. |
MqttMessageId | int | The MQTT MID (Message Id) from the MQTT server. |
Id | int | Optional - If a random Id was sent in the unsubscribe request, the same Id will be returned here for matching. |