For MK3.5/3.9/5 you cannot use single print profile. You MUST use use the MMU profile with a single filament, what you pick doesn't matter, we will overwrite the filament with the tool you choose.
Description: This plugin adds Prusa MMU support to OctoPrint. The active filament will be
displayed in the navbar and you will be prompted to select which filament to use when slicing in
"MMU Single" mode. Other settings are available to name each tool and set defaults. This plugin
only works for Prusa printers with an MMU. Supports MK3s/3.5/3.9/4 MMU3 firmware 3.X.X
.
This plugin was inspired by the MMU2filamentselect plugin. I wanted to try and take it a step further.
Install via the bundled Plugin Manager or manually by selecting the latest zip:
https://github.com/jukebox42/Octoprint-PrusaMMU/releases/latest/download/Octoprint-PrusaMmu.zip
This plugin does some minimal gcode manipulation. This is how it detects tool events and pause the print to provide the dialog.
The command interactions are as follows:
Tx
: When the GCODE would send a Tx
(tool change) it first triggers the modal and then does
not send the Tx
command. Instead, it sends a pause event to the printer. This results in Prusa
not prompting for a tool change. If the timeout time is reached (_timeout_prompt
) then the
plugin resends the Tx
command to allow Prusa to prompt the user.M109
: When the GCODE would send an M109
(Wait for Hotend Temperature) and the user has
selected a filament it sends both the M109
and T#
(like T2
), otherwise it just sends the
M109
.T#
: If the filament remap is enabled it will intercept a T#
command and alter the number to
match the one provided in settings.T#
command it sets the tool internally, so it can be used to
display. This is to support multicolor printing. This trigger is also used to show unloading.Note Prusa removed the single print profile which served a Tx
we use to do the detection. We use
something different for MK3.5+. For MK3.5+ you cannot use single print
profile. You MUST use use the MMU profile with a single filament, what you pick doesn't matter, we
will overwrite the filament with the tool you choose.
When a print is started, the print is immediately pause and the user is prompted to select a
filament. The plugin then stores the selected option and each time a T#
is encountered, it
rewrites the command to the chosen tool. If the dialog times out, the print will continue with the
sliced tool. This behavior varies from the MK3 which will pause at the printer.
This does mean you will always get the prompt modal for every print, but you can click skip and have it preserve the default behavior. In a future release, I will try to read ahead and figure out if only one tool was used in the profile.
The MMU 3.X.X firmware communicates continuously with the printer. The printer sends the MMU requests, and the MMU sends back responses. The MMU's responses start with the request letter and data, so it just listens for the Responses.
MMU 3.X.X responses come in this format:
MMU2:<(Request Letter)(Request Data) (Response Letter)(Response Data)
(Request Letter)
- A single letter code that represents a request sent from the printer to the MMU.
T
- Tool, L
- Load, U
- Unload, X
- Reset, K
- Cut, and E
- Eject.(Request Data)
- Hexidecimal data that follows the Request Letter.
0
, unless the request involves filament, in which case it is the filament number [0-4]
.(Response Letter)
- A single letter code that represents a response from the MMU.
P
- Processing, E
- Error, F
- Finished, A
- Accepted,
R
- Rejected, and B
- Button.(Response Data)
- Hexidecimal data that follows the Response Letter.
P
- Progress messages, and E
- Error messagesSeveral Regex strings are used to parse the MMU 3.X.X responses:
MMU2:<[TLUXKE]
- Generic Regex used to catch the responses with the Request Letters that are important.MMU2:<([TLUXKE])(.*) ([PEFARB])(.*)\*
- Used to split the command into the four groups described above.Additionally, it also listens for these lines:
MMU2:Saving and parking
- Used to detect when the printer is waiting for user input after the
MMU fails at auto-retrying after an Error.MMU2:Heater cooldown pending
- The same as above. Might be unnecessary, but included just in case.LCD status changed
- If the printer was paused, this indicates that the pause is probably over.For all instances where command manipulation happens see __init__.py
for Gcode Hooks
. Also
look at function _timeout_prompt
where it handles unpausing the printer after the timer and either
sending a Tx
or T#
if useDefaultFilament
and defaultFilament
settings are set.
It listens to printer responses and does some substring matching. This is done to identify filament
events and printer notifications, so it can update the navbar: (gcode_received_hook
)
MACHINE_TYPE:Prusa-MK(3\.5|3\.9|4)
- Used to detect if the printer is an MK3.5/3.9/4.MMU2:ERR Wait for User
- Paused for user. Used to show the printer needs attention.MMU2:Feeding to FINDA
- Indicates loading to the Finda.MMU2:Feeding to extruder
- Indicates loading to the Extruder.MMU2:Feeding to FSensor
- Indicates loading to the FSensor.MMU2:Unloading to FINDA
- Indicates filament is unloading.MMU2:Retract from FINDA
- Indicates the final unloading, the print is done.MMU2:Disengaging idler
- This indicates when a task completes (like loading/unloading)MMU2:Command Error
- Displays there's an MMU error. Error is generic and not parsed.MMU2:ERR Help filament
- Displays there's an MMU error. Error is generic and not parsed.MMU2:ERR Internal
- Displays there's an MMU error. Error is generic and not parsed.MMU2:ERR TMC failed
- Displays there's an MMU error. Error is generic and not parsed.MK3
printers will look like MK3S
in the debug logs. They operate the same, this was easier
to implement.Prusa Version
option in settings to fix it to a version.Here is a list of states used internally. These will be the state
value in events.
NOT_FOUND
- MMU not found, this is an initial state before a printer connects.STARTING
- When a printer with an MMU is connected it goes through a startup. This is triggered
first followed by OK
when it replies it's enabled.OK
- Triggered when a print job finishes (or cancels) and when the mmu reports healthy on
printer connect.LOADED
- Filament (tool) is loaded.UNLOADING
- Filament (tool) is unloading.LOADING
- Filament (tool) is loading OR unloading has concluded.PAUSED_USER
- Printer is awaiting user input OR filament dialog is present.ATTENTION
- Printer needs user attention, could be MMU error or printer prompt (like new
software version available).LOADING_MMU
- MMU is preloading filiment to the MMU (not to nozzle).CUTTING
- MMU is cutting the filament.EJECTING
- MMU is ejecting the filament.UNLOADING_FINAL
- MMU is performing a final unload. This is only for the MK4 and replaced with a
UNLOADING
when sent to the client. Used to do the final unload cleanup.New when using MK3s MMU 3.0.0! (Not available for MK4 users)
When the MMU throws an error you'll see a command come across like MMU2:<X0 E800d
. The E
Response Letter represents there being an Error and the 800d
is the hex Response Data of the error.
We map those hex codes in static/mmuErrors.js
to get the details about the errors. Mapping was
done by hand (i'll automate it eventually). To get the url of the error you just need to append the
code
value from the MMU2MmuErrorStrings
map to https://prusa.io/
like https://prusa.io/04306
.
A number of events are fired you can listen to.
plugin_prusammu_mmu_changed
MMU data changed; Either state, tool, previous tool, response, or response data was updated.
Payload:
{
state: string
tool: int
previousTool: int
response: string
responseData: string
prusaVersion: string
}
plugin_prusammu_mmu_change
MMU data may change. This is fired by a number of things internal to the plugin, what's important
is that this does not indicate a change happened, just that one may happen. It's strongly
recommended to listen on plugin_prusammu_mmu_changed
instead unless you need to react before a
change occurs. The plugin internally dedupes these events by comparing the new with the old and only
triggering when there's a change.
Payload:
{
state: string
tool: int
previousTool: int
response: string
responseData: string
prusaVersion: string
}
plugin_prusammu_show_prompt
The plugin heard a Tx
(or a print was started if you use are using an MK4) and needs to prompt
the user to pick the filament.
Payload: None
plugin_prusammu_refresh_nav
Used to force the UI to refresh it's MMU data (like on page refresh).
Payload: None
This plugin makes use of simpleApiCommand
for some instances to stay up to date. You can use these
endpoints yourself if you want to get information about the MMU via a POST.
<octoprint server>/api/plugin/prusammu
getmmu
Call to get the current state of the MMU.
Request:
{ "command": "getmmu" }
Response:
{
lastLine: string
state: string
tool: int
previousTool: int
response: string
responseData: string
prusaVersion: string
}
Response: None
A small set of javascript functions are available to interact with. Look at the getFilamentList()
function for how you can interact with them.
getFilamentList()
Returns the filament array. This will contain all the filament data based on the source selected. This is what's used to get the data for the prompt as well as navbar item. The resultset may include 1-5 entries based on what's specified by the source.
Returns:
[
{id: 1, index: 0, name: "", type: "", color: "", enabled: true},
{id: 2, index: 1, name: "", type: "", color: "", enabled: true},
{id: 3, index: 2, name: "", type: "", color: "", enabled: true},
{id: 4, index: 3, name: "", type: "", color: "", enabled: true},
{id: 5, index: 4, name: "", type: "", color: "", enabled: true},
]
Filament object properties:
id
- The ID of the filament (the index +1, so it's readable and because I wanted to make it hard
on myself)index
- The real index of the filament (tool) as the printer would see it.name
- The name the user gave the filament.type
- The type of filament (i.e. PLA/PETG). This is blank unless the source is filamentManager
or spoolManager.color
- The color of the filament.enabled
Whether the filament is enabled in prusammu (when using prusammu as the source).processMmuProgress(responseData)
Given the progress code it returns a string containing the progress message.
If the value of responseData
is one of [P
, E
, F
, A
, R
] than you can pass responseData
to get more details about the progress like "Unloading to FINDA"
.
Returns: string
processMmuError(responseData)
Given the error code it generates an error object with more information.
If the value of response
is E
(Error) you can send this function responseData
to get the
error details.
Returns:
{
code: "04401",
title: "MMU NOT RESPONDING",
text: "MMU not responding. Check the wiring and connectors.",
url: `https://prusa.io/802e`,
}
Object properties:
code
- The error code.title
- The name of the error.text
- The description of the error.url
- The Prusa short url of the error. These are formatted like: https://prusa.io/{code}
.If you too would like to add your filament/spool manager as a valid source for this plugin you need to update the following areas:
__init__.py
on_after_startup()
to detect your plugin.templates/prusammu_settings.jinja2
Filament Label Source
.alert
box identifying how filament is set in your plugin.static/prusammu.js
PrusaMMU2ViewModel
(bottom of file) self.filamentSources
object.getFilamentList()
function to call your filament/spool function. This will require
your plugin to expose a javascript function the returns a list of filament and what tool they
represent.Enable debug logs via the settings menu, ensure logging is set to the debug level for prusammu. Note: This may slow down printing.
Octoprint exposes the viewmodel via:
> OctoPrint.coreui.viewmodels.prusaMMU2ViewModel
You can manually build this project into a zip by running:
$ bash build.sh [VERSION]
# ex:
$ bash build.sh 2022.7.4
=== Building PrusaMMU ===
Settings:
- Version: 2022.7.4
Writing plugin version... done
Disabling debug... done
Zipping... done
Done.
Versioning is done by date, so it's clear when the build was installed and made available. Year is
four characters long. Month is one or two characters long and does not have a leading zero
for sub ten. Day follows the same rules as month. Beta versions are denoted by a "b" directly
following the day and then a number describing what beta version it is. Sequentially 2022.1.1a0
comes before 2022.1.1
.
Format:
YYYY.M.D
YYYY.M.Da#
Examples:
2022.10.4
2022.1.20
2022.1.20a0
I built this plugin for fun, and because I wanted better MMU support. If you catch a bug or think it needs some work feel free to open a PR or cut an issue, and I'll do my best to review it.
You know how some software grows organically and by the time you realize it's gotten out of control it's too late? Yeah that's this. Sorry in advance for those of you trying to parse the code.
Special thanks to: