Merge branch 'main' into PostProcessing_InsertAtLayerChange_update

This commit is contained in:
Erwan MATHIEU 2025-06-16 10:24:18 +02:00 committed by GitHub
commit facf0b7d4a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
213 changed files with 7866 additions and 582 deletions

View file

@ -5,38 +5,25 @@ body:
- type: markdown
attributes:
value: |
### ✨Try our improved Cura 5.7
Before filling out the report below, we want you to try the latest Cura 5.7.
This version of Cura has become significantly more reliable and has an updated slicing engine that will automatically send a report to the Cura Team for analysis.
#### [You can find the downloads here](https://github.com/Ultimaker/Cura/releases/latest) ####
If you still encounter a crash you are still welcome to report the issue so we can use your model as a test case, you can find instructions on how to do that below.
### ✨Are you stuck? Have you tried these two things?
1- Are you on a Cura version lower than Cura 5.7? We really recommend updating because it resolves a lot of slicing crashes!
2- Have you tried fixing the model with software that repairs 3d files and makes them watertight?
Are you seeing spots and dots on your model? That is Cura indicating that your model is not watertight.
You can try doing a quick [Mesh Fix with the Meshtools Plugin](https://marketplace.ultimaker.com/app/cura/plugins/fieldofview/MeshTools) or other mesh editing software.
### Project File
**⚠️ Before you continue, we need your project file to troubleshoot a slicing crash.**
It contains the printer and settings we need for troubleshooting.
If you still encounter a crash you are welcome to report the issue so we can use your model as a test case.
You can find instructions on how to share your model in a Package for Technical Support below.
![Alt Text](https://user-images.githubusercontent.com/40423138/240616958-5a9751f2-bd34-4808-9752-6fde2e27516e.gif)
To save a project file go to File -> Save project.
Please make sure to .zip your project file.
For big files, you may need to use [WeTransfer](https://wetransfer.com/) or similar file-sharing sites.
🤔 Before you share, please think to yourself. Is this a model that can be shared?
Unfortunately we cannot help if this file is missing.
Do you have the project file? Than let's continue ⬇️
### Questions
🤔 Before you share, please think to yourself. Is this a model that can be shared on the internet?
**Unfortunately, we cannot help if this file is missing.**
### Questions
- type: input
attributes:
label: Cura Version
placeholder: 5.6.0
description: We work hard on improving our slicing crashes. If you are not on the latest version of Cura, [you can download it here](https://github.com/Ultimaker/Cura/releases/latest)
validations:
required: true
- type: markdown
attributes:
value: |
We work hard on improving our slicing crashes. Our most recent release is 5.7.1.
If you are not on the latest version of Cura, [you can download it here](https://github.com/Ultimaker/Cura/releases/latest)
- type: input
attributes:
label: Operating System
@ -50,27 +37,13 @@ body:
description: Which printer was selected in Cura?
validations:
required: true
- type: input
attributes:
label: Name abnormal settings
description: Are there any settings that you might have changed that caused the crash? Does your model slice when you select the default profiles?
placeholder:
validations:
- type: input
attributes:
label: Describe model location
description: Does your model slice if you rotate the model 90 degrees or if you move it away from the center of the buildplate?
placeholder:
validations:
- type: input
attributes:
label: Describe your model
description: Have you sliced your model succesfully before? Is it watertight? Have you tried doing a quick [Mesh Fix with the Meshtools Plugin](https://marketplace.ultimaker.com/app/cura/plugins/fieldofview/MeshTools)?
validations:
required: true
- type: textarea
attributes:
label: Add your .zip here ⬇️
description: You can add the zip file and additional information that is relevant to the issue in the comments below.
label: Describe your problem and add the package for technical support as a .zip here ⬇️
description: |
If you still have Cura open with your crash > Click on Help on top bar > Click on Export Package For Technical Support > Compress the file into a zip > Add the file here to your GitHub issue 🔗
If you closed Cura, please open Cura to recreate the crash> Select your printer > Load your model > Select your print settings > Click on Help on top bar > Click on Export Package For Technical Support > Compress the file into a zip > Add the file here to your GitHub issue 🔗
validations:
required: true

View file

@ -1,10 +1,10 @@
name: Nightly build - stable release
run-name: Nightly build - stable release
on:
schedule:
# Daily at 5:15 CET
- cron: '15 4 * * *'
# on:
# schedule:
# # Daily at 5:15 CET
# - cron: '15 4 * * *'
jobs:
build-nightly:

View file

@ -1,10 +1,10 @@
name: Nightly build - dev release
run-name: Nightly build - dev release
on:
schedule:
# Daily at 4:15 CET
- cron: '15 3 * * *'
# on:
# schedule:
# # Daily at 4:15 CET
# - cron: '15 3 * * *'
jobs:
build-nightly:

View file

@ -6,11 +6,11 @@ requirements:
- "cura_binary_data/5.11.0-alpha.0@ultimaker/testing"
- "fdm_materials/5.11.0-alpha.0@ultimaker/testing"
- "dulcificum/5.10.0"
- "pysavitar/5.10.0"
- "pysavitar/5.11.0-alpha.0"
- "pynest2d/5.10.0"
requirements_internal:
- "fdm_materials/5.11.0-alpha.0@ultimaker/testing"
- "cura_private_data/5.10.0-alpha.0@internal/testing"
- "cura_private_data/5.11.0-alpha.0@internal/testing"
requirements_enterprise:
- "native_cad_plugin/2.0.0"
urls:

View file

@ -1,8 +1,10 @@
import json
import os
import requests
import yaml
import tempfile
import tarfile
from datetime import datetime
from io import StringIO
from pathlib import Path
from git import Repo
@ -562,6 +564,30 @@ class CuraConan(ConanFile):
self.cpp.package.bindirs = ["bin"]
self.cpp.package.resdirs = ["resources", "plugins", "packaging"]
def _make_internal_distinct(self):
test_colors_path = Path(self.source_folder, "resources", "themes", "daily_test_colors.json")
if not test_colors_path.exists():
print(f"Could not find '{str(test_colors_path)}'. Won't generate rotating colors for alpha builds.")
return
if "alpha" in self.version:
with test_colors_path.open("r") as test_colors_file:
test_colors = json.load(test_colors_file)
biweekly_day = (datetime.now() - datetime(2025, 3, 14)).days % len(test_colors)
for theme_dir in Path(self.source_folder, "resources", "themes").iterdir():
if not theme_dir.is_dir():
continue
theme_path = Path(theme_dir, "theme.json")
if not theme_path.exists():
print(f"('Colorize-by-day' alpha builds): Skipping {str(theme_path)}, could not find file.")
continue
with theme_path.open("r") as theme_file:
theme = json.load(theme_file)
if theme["colors"]:
theme["colors"]["main_window_header_background"] = test_colors[biweekly_day]
with theme_path.open("w") as theme_file:
json.dump(theme, theme_file)
test_colors_path.unlink()
def generate(self):
copy(self, "cura_app.py", self.source_folder, str(self._script_dir))
@ -581,6 +607,9 @@ class CuraConan(ConanFile):
copy(self, "bundled_*.json", native_cad_plugin.resdirs[1],
str(Path(self.source_folder, "resources", "bundled_packages")), keep_path = False)
# Make internal versions built on different days distinct, so people don't get confused while testing.
self._make_internal_distinct()
# Copy resources of cura_binary_data
cura_binary_data = self.dependencies["cura_binary_data"].cpp_info
copy(self, "*", cura_binary_data.resdirs[0], str(self._share_dir.joinpath("cura")), keep_path = True)

View file

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Tuple, Optional, TYPE_CHECKING, Dict, Any
@ -9,14 +9,10 @@ if TYPE_CHECKING:
class Backups:
"""The back-ups API provides a version-proof bridge between Cura's
BackupManager and plug-ins that hook into it.
"""The back-ups API provides a version-proof bridge between Cura's BackupManager and plug-ins that hook into it.
Usage:
.. code-block:: python
from cura.API import CuraAPI
api = CuraAPI()
api.backups.createBackup()
@ -26,19 +22,22 @@ class Backups:
def __init__(self, application: "CuraApplication") -> None:
self.manager = BackupsManager(application)
def createBackup(self) -> Tuple[Optional[bytes], Optional[Dict[str, Any]]]:
def createBackup(self, available_remote_plugins: frozenset[str] = frozenset()) -> Tuple[Optional[bytes], Optional[Dict[str, Any]]]:
"""Create a new back-up using the BackupsManager.
:return: Tuple containing a ZIP file with the back-up data and a dict with metadata about the back-up.
"""
return self.manager.createBackup()
return self.manager.createBackup(available_remote_plugins)
def restoreBackup(self, zip_file: bytes, meta_data: Dict[str, Any]) -> None:
def restoreBackup(self, zip_file: bytes, meta_data: Dict[str, Any], auto_close: bool = True) -> None:
"""Restore a back-up using the BackupsManager.
:param zip_file: A ZIP file containing the actual back-up data.
:param meta_data: Some metadata needed for restoring a back-up, like the Cura version number.
"""
return self.manager.restoreBackup(zip_file, meta_data)
return self.manager.restoreBackup(zip_file, meta_data, auto_close=auto_close)
def shouldReinstallDownloadablePlugins(self) -> bool:
return self.manager.shouldReinstallDownloadablePlugins()

View file

@ -3,7 +3,7 @@
from dataclasses import asdict
from typing import cast, Dict, TYPE_CHECKING
from typing import cast, Dict, TYPE_CHECKING, Any
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.SettingFunction import SettingFunction
@ -54,6 +54,15 @@ class Settings:
return self.application.getSidebarCustomMenuItems()
def getAllGlobalSettings(self) -> Dict[str, Any]:
global_stack = cast(GlobalStack, self.application.getGlobalContainerStack())
all_settings = {}
for setting in global_stack.getAllKeys():
all_settings[setting] = self._retrieveValue(global_stack, setting)
return all_settings
def getSliceMetadata(self) -> Dict[str, Dict[str, Dict[str, str]]]:
"""Get all changed settings and all settings. For each extruder and the global stack"""
print_information = self.application.getPrintInformation()
@ -71,24 +80,16 @@ class Settings:
"quality": asdict(machine_manager.activeQualityDisplayNameMap()),
}
def _retrieveValue(container: InstanceContainer, setting_: str):
value_ = container.getProperty(setting_, "value")
for _ in range(0, 1024): # Prevent possibly endless loop by not using a limit.
if not isinstance(value_, SettingFunction):
return value_ # Success!
value_ = value_(container)
return 0 # Fallback value after breaking possibly endless loop.
global_stack = cast(GlobalStack, self.application.getGlobalContainerStack())
# Add global user or quality changes
global_flattened_changes = InstanceContainer.createMergedInstanceContainer(global_stack.userChanges, global_stack.qualityChanges)
for setting in global_flattened_changes.getAllKeys():
settings["global"]["changes"][setting] = _retrieveValue(global_flattened_changes, setting)
settings["global"]["changes"][setting] = self._retrieveValue(global_flattened_changes, setting)
# Get global all settings values without user or quality changes
for setting in global_stack.getAllKeys():
settings["global"]["all_settings"][setting] = _retrieveValue(global_stack, setting)
settings["global"]["all_settings"][setting] = self._retrieveValue(global_stack, setting)
for i, extruder in enumerate(global_stack.extruderList):
# Add extruder fields to settings dictionary
@ -100,10 +101,19 @@ class Settings:
# Add extruder user or quality changes
extruder_flattened_changes = InstanceContainer.createMergedInstanceContainer(extruder.userChanges, extruder.qualityChanges)
for setting in extruder_flattened_changes.getAllKeys():
settings[f"extruder_{i}"]["changes"][setting] = _retrieveValue(extruder_flattened_changes, setting)
settings[f"extruder_{i}"]["changes"][setting] = self._retrieveValue(extruder_flattened_changes, setting)
# Get extruder all settings values without user or quality changes
for setting in extruder.getAllKeys():
settings[f"extruder_{i}"]["all_settings"][setting] = _retrieveValue(extruder, setting)
settings[f"extruder_{i}"]["all_settings"][setting] = self._retrieveValue(extruder, setting)
return settings
@staticmethod
def _retrieveValue(container: InstanceContainer, setting_: str):
value_ = container.getProperty(setting_, "value")
for _ in range(0, 1024): # Prevent possibly endless loop by not using a limit.
if not isinstance(value_, SettingFunction):
return value_ # Success!
value_ = value_(container)
return 0 # Fallback value after breaking possibly endless loop.

View file

@ -1,5 +1,8 @@
# Copyright (c) 2021 Ultimaker B.V.
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import tempfile
import json
import io
import os
@ -7,12 +10,13 @@ import re
import shutil
from copy import deepcopy
from zipfile import ZipFile, ZIP_DEFLATED, BadZipfile
from typing import Dict, Optional, TYPE_CHECKING, List
from typing import Callable, Dict, Optional, TYPE_CHECKING, List
from UM import i18nCatalog
from UM.Logger import Logger
from UM.Message import Message
from UM.Platform import Platform
from UM.PluginRegistry import PluginRegistry
from UM.Resources import Resources
from UM.Version import Version
@ -30,6 +34,7 @@ class Backup:
"""These files should be ignored when making a backup."""
IGNORED_FOLDERS = [] # type: List[str]
"""These folders should be ignored when making a backup."""
SECRETS_SETTINGS = ["general/ultimaker_auth_data"]
"""Secret preferences that need to obfuscated when making a backup of Cura"""
@ -42,7 +47,7 @@ class Backup:
self.zip_file = zip_file # type: Optional[bytes]
self.meta_data = meta_data # type: Optional[Dict[str, str]]
def makeFromCurrent(self) -> None:
def makeFromCurrent(self, available_remote_plugins: frozenset[str] = frozenset()) -> None:
"""Create a back-up from the current user config folder."""
cura_release = self._application.getVersion()
@ -68,7 +73,7 @@ class Backup:
# Create an empty buffer and write the archive to it.
buffer = io.BytesIO()
archive = self._makeArchive(buffer, version_data_dir)
archive = self._makeArchive(buffer, version_data_dir, available_remote_plugins)
if archive is None:
return
files = archive.namelist()
@ -77,9 +82,7 @@ class Backup:
machine_count = max(len([s for s in files if "machine_instances/" in s]) - 1, 0) # If people delete their profiles but not their preferences, it can still make a backup, and report -1 profiles. Server crashes on this.
material_count = max(len([s for s in files if "materials/" in s]) - 1, 0)
profile_count = max(len([s for s in files if "quality_changes/" in s]) - 1, 0)
# We don't store plugins anymore, since if you can make backups, you have an account (and the plugins are
# on the marketplace anyway)
plugin_count = 0
plugin_count = len([s for s in files if "plugin.json" in s])
# Store the archive and metadata so the BackupManager can fetch them when needed.
self.zip_file = buffer.getvalue()
self.meta_data = {
@ -92,22 +95,72 @@ class Backup:
# Restore the obfuscated settings
self._illuminate(**secrets)
def _makeArchive(self, buffer: "io.BytesIO", root_path: str) -> Optional[ZipFile]:
def _fillToInstallsJson(self, file_path: str, reinstall_on_restore: frozenset[str], add_to_archive: Callable[[str, str], None]) -> Optional[str]:
""" Moves all plugin-data (in a config-file) for plugins that could be (re)installed from the Marketplace from
'installed' to 'to_installs' before adding that file to the archive.
Note that the 'filename'-entry in the package-data (of the plugins) might not be valid anymore on restore.
We'll replace it on restore instead, as that's the time when the new package is downloaded.
:param file_path: Absolute path to the packages-file.
:param reinstall_on_restore: A set of plugins that _can_ be reinstalled from the Marketplace.
:param add_to_archive: A function/lambda that takes a filename and adds it to the archive (as the 2nd name).
"""
with open(file_path, "r") as file:
data = json.load(file)
reinstall, keep_in = {}, {}
for install_id, install_info in data["installed"].items():
(reinstall if install_id in reinstall_on_restore else keep_in)[install_id] = install_info
data["installed"] = keep_in
data["to_install"].update(reinstall)
if data is not None:
tmpfile = tempfile.NamedTemporaryFile(delete_on_close=False)
with open(tmpfile.name, "w") as outfile:
json.dump(data, outfile)
add_to_archive(tmpfile.name, file_path)
return tmpfile.name
return None
def _findRedownloadablePlugins(self, available_remote_plugins: frozenset) -> (frozenset[str], frozenset[str]):
""" Find all plugins that should be able to be reinstalled from the Marketplace.
:param plugins_path: Path to all plugins in the user-space.
:return: Tuple of a set of plugin-ids and a set of plugin-paths.
"""
plugin_reg = PluginRegistry.getInstance()
id = "id"
plugins = [v for v in plugin_reg.getAllMetaData()
if v[id] in available_remote_plugins and not plugin_reg.isBundledPlugin(v[id])]
return frozenset([v[id] for v in plugins]), frozenset([v["location"] for v in plugins])
def _makeArchive(self, buffer: "io.BytesIO", root_path: str, available_remote_plugins: frozenset) -> Optional[ZipFile]:
"""Make a full archive from the given root path with the given name.
:param root_path: The root directory to archive recursively.
:return: The archive as bytes.
"""
ignore_string = re.compile("|".join(self.IGNORED_FILES + self.IGNORED_FOLDERS))
reinstall_instead_ids, reinstall_instead_paths = self._findRedownloadablePlugins(available_remote_plugins)
tmpfiles = []
try:
archive = ZipFile(buffer, "w", ZIP_DEFLATED)
for root, folders, files in os.walk(root_path):
add_path_to_archive = lambda path, alt_path: archive.write(path, alt_path[len(root_path) + len(os.sep):])
for root, folders, files in os.walk(root_path, topdown=True):
for item_name in folders + files:
absolute_path = os.path.join(root, item_name)
if ignore_string.search(absolute_path):
if ignore_string.search(absolute_path) or any([absolute_path.startswith(x) for x in reinstall_instead_paths]):
continue
archive.write(absolute_path, absolute_path[len(root_path) + len(os.sep):])
if item_name == "packages.json":
tmpfiles.append(
self._fillToInstallsJson(absolute_path, reinstall_instead_ids, add_path_to_archive))
else:
add_path_to_archive(absolute_path, absolute_path)
archive.close()
for tmpfile_path in tmpfiles:
try:
os.remove(tmpfile_path)
except IOError as ex:
Logger.warning(f"Couldn't remove temporary file '{tmpfile_path}' because '{ex}'.")
return archive
except (IOError, OSError, BadZipfile) as error:
Logger.log("e", "Could not create archive from user data directory: %s", error)

View file

@ -1,4 +1,4 @@
# Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from typing import Dict, Optional, Tuple, TYPE_CHECKING
@ -22,7 +22,10 @@ class BackupsManager:
def __init__(self, application: "CuraApplication") -> None:
self._application = application
def createBackup(self) -> Tuple[Optional[bytes], Optional[Dict[str, str]]]:
def shouldReinstallDownloadablePlugins(self) -> bool:
return True
def createBackup(self, available_remote_plugins: frozenset[str] = frozenset()) -> Tuple[Optional[bytes], Optional[Dict[str, str]]]:
"""
Get a back-up of the current configuration.
@ -31,17 +34,18 @@ class BackupsManager:
self._disableAutoSave()
backup = Backup(self._application)
backup.makeFromCurrent()
backup.makeFromCurrent(available_remote_plugins if self.shouldReinstallDownloadablePlugins() else frozenset())
self._enableAutoSave()
# We don't return a Backup here because we want plugins only to interact with our API and not full objects.
return backup.zip_file, backup.meta_data
def restoreBackup(self, zip_file: bytes, meta_data: Dict[str, str]) -> None:
def restoreBackup(self, zip_file: bytes, meta_data: Dict[str, str], auto_close: bool = True) -> None:
"""
Restore a back-up from a given ZipFile.
:param zip_file: A bytes object containing the actual back-up.
:param meta_data: A dict containing some metadata that is needed to restore the back-up correctly.
:param auto_close: Normally, Cura will need to close immediately after restoring the back-up.
"""
if not meta_data.get("cura_release", None):
@ -54,7 +58,7 @@ class BackupsManager:
backup = Backup(self._application, zip_file = zip_file, meta_data = meta_data)
restored = backup.restore()
if restored:
if restored and auto_close:
# At this point, Cura will need to restart for the changes to take effect.
# We don't want to store the data at this point as that would override the just-restored backup.
self._application.windowClosed(save_data = False)

View file

@ -188,6 +188,7 @@ class CuraApplication(QtApplication):
self._single_instance = None
self._open_project_mode: Optional[str] = None
self._read_operation_is_project_file: Optional[bool] = None
self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions]
@ -1894,36 +1895,39 @@ class CuraApplication(QtApplication):
query = QUrlQuery(url.query())
model_url = QUrl(query.queryItemValue("file", options=QUrl.ComponentFormattingOption.FullyDecoded))
def on_finish(response):
content_disposition_header_key = QByteArray("content-disposition".encode())
filename = model_url.path().split("/")[-1] + ".stl"
if response.hasRawHeader(content_disposition_header_key):
# content_disposition is in the format
# ```
# content_disposition attachment; filename="[FILENAME]"
# ```
# Use a regex to extract the filename
content_disposition = str(response.rawHeader(content_disposition_header_key).data(),
encoding='utf-8')
content_disposition_match = re.match(r'attachment; filename=(?P<filename>.*)',
content_disposition)
if content_disposition_match is not None:
filename = content_disposition_match.group("filename").strip("\"")
tmp = tempfile.NamedTemporaryFile(suffix=filename, delete=False)
with open(tmp.name, "wb") as f:
f.write(response.readAll())
self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False)
def on_error(*args, **kwargs):
Logger.log("w", "Could not download file from {0}".format(model_url.url()))
Message("Could not download file: " + str(model_url.url()),
Logger.warning(f"Could not download file from {model_url.url()}")
Message(f"Could not download file: {str(model_url.url())}",
title= "Loading Model failed",
message_type=Message.MessageType.ERROR).show()
return
def on_finish(response):
try:
content_disposition_header_key = QByteArray("content-disposition".encode())
filename = model_url.path().split("/")[-1] + ".stl"
if response.hasRawHeader(content_disposition_header_key):
# content_disposition is in the format
# ```
# content_disposition attachment; filename="[FILENAME]"
# ```
# Use a regex to extract the filename
content_disposition = str(response.rawHeader(content_disposition_header_key).data(),
encoding='utf-8')
content_disposition_match = re.match(r'attachment; filename=(?P<filename>.*)',
content_disposition)
if content_disposition_match is not None:
filename = content_disposition_match.group("filename").strip("\"")
tmp = tempfile.NamedTemporaryFile(suffix=filename, delete=False)
with open(tmp.name, "wb") as f:
f.write(response.readAll())
self.readLocalFile(QUrl.fromLocalFile(tmp.name), add_to_recent_files=False)
except Exception as ex:
Logger.warning(f"Exception {str(ex)}")
on_error()
self.getHttpRequestManager().get(
model_url.url(),
@ -2015,18 +2019,18 @@ class CuraApplication(QtApplication):
self.deleteAll()
break
is_project_file = self.checkIsValidProjectFile(file)
self._read_operation_is_project_file = self.checkIsValidProjectFile(file)
if self._open_project_mode is None:
self._open_project_mode = self.getPreferences().getValue("cura/choice_on_open_project")
if is_project_file and self._open_project_mode == "open_as_project":
if self._read_operation_is_project_file and self._open_project_mode == "open_as_project":
# open as project immediately without presenting a dialog
workspace_handler = self.getWorkspaceFileHandler()
workspace_handler.readLocalFile(file, add_to_recent_files_hint = add_to_recent_files)
return
if is_project_file and self._open_project_mode == "always_ask":
if self._read_operation_is_project_file and self._open_project_mode == "always_ask":
# present a dialog asking to open as project or import models
self.callLater(self.openProjectFile.emit, file, add_to_recent_files)
return
@ -2164,7 +2168,7 @@ class CuraApplication(QtApplication):
nodes_to_arrange.append(node)
# If the file is a project,and models are to be loaded from a that project,
# models inside file should be arranged in buildplate.
elif self._open_project_mode == "open_as_model":
elif self._read_operation_is_project_file and self._open_project_mode == "open_as_model":
nodes_to_arrange.append(node)
# This node is deep copied from some other node which already has a BuildPlateDecorator, but the deepcopy

View file

@ -402,6 +402,9 @@ class CuraContainerStack(ContainerStack):
return super().getProperty(key, property_name, context)
def getValue(self, key: str, context = None) -> Any:
return self.getProperty(key, "value", context)
class _ContainerIndexes:
"""Private helper class to keep track of container positions and their types."""

View file

@ -15,6 +15,7 @@ from UM.Scene.Selection import Selection
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from UM.Settings.ContainerRegistry import ContainerRegistry # Finding containers by ID.
from cura.Machines.ContainerTree import ContainerTree
from cura.Settings.ExtruderStack import ExtruderStack
from typing import Any, cast, Dict, List, Optional, TYPE_CHECKING, Union
@ -304,6 +305,11 @@ class ExtruderManager(QObject):
Logger.log("e", "Unable to find one or more of the extruders in %s", used_extruder_stack_ids)
return []
def getFirstUsedExtruderStack(self)-> ExtruderStack:
used_extruders = self.getUsedExtruderStacks()
sorted_extruders = sorted(used_extruders, key=lambda extruder: extruder.getValue("extruder_nr"))
return sorted_extruders[0]
def getInitialExtruderNr(self) -> int:
"""Get the extruder that the print will start with.
@ -320,8 +326,7 @@ class ExtruderManager(QObject):
skirt_brim_extruder_nr = global_stack.getProperty("skirt_brim_extruder_nr", "value")
# if the skirt_brim_extruder_nr is -1, then we use the first used extruder
if skirt_brim_extruder_nr == -1:
used_extruders = self.getUsedExtruderStacks()
return used_extruders[0].position
return self.getFirstUsedExtruderStack().getValue("extruder_nr")
else:
return skirt_brim_extruder_nr
if adhesion_type == "raft":
@ -332,7 +337,7 @@ class ExtruderManager(QObject):
return global_stack.getProperty("support_infill_extruder_nr", "value")
# REALLY no adhesion? Use the first used extruder.
return self.getUsedExtruderStacks()[0].getProperty("extruder_nr", "value")
return self.getFirstUsedExtruderStack().getValue("extruder_nr")
def removeMachineExtruders(self, machine_id: str) -> None:
"""Removes the container stack and user profile for the extruders for a specific machine.

View file

@ -1,9 +1,8 @@
# Copyright (c) 2022 UltiMaker B.V.
# Copyright (c) 2025 UltiMaker
# Cura's build system is released under the terms of the AGPLv3 or higher.
!define APP_NAME "{{ app_name }}"
!define COMP_NAME "{{ company }}"
!define WEB_SITE "{{ web_site }}"
!define VERSION "{{ version }}"
!define VIVERSION "{{ version_major }}.{{ version_minor }}.{{ version_patch }}.0"
!define COPYRIGHT "Copyright (c) {{ year }} {{ company }}"
@ -16,13 +15,11 @@
!define REG_APP_PATH "Software\Microsoft\Windows\CurrentVersion\App Paths\${APP_NAME}-${VERSION}"
!define UNINSTALL_PATH "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}-${VERSION}"
!define REG_START_MENU "Start Menu Folder"
!define REG_START_MENU "Start Menu Shortcut"
;Require administrator access
RequestExecutionLevel admin
var SM_Folder
######################################################################
VIProductVersion "${VIVERSION}"
@ -64,11 +61,9 @@ InstallDir "$PROGRAMFILES64\${APP_NAME}"
!ifdef REG_START_MENU
!define MUI_STARTMENUPAGE_NODISABLE
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "UltiMaker Cura"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${REG_ROOT}"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${UNINSTALL_PATH}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${REG_START_MENU}"
!insertmacro MUI_PAGE_STARTMENU Application $SM_Folder
!endif
!insertmacro MUI_PAGE_INSTFILES
@ -107,27 +102,11 @@ SetOutPath "$INSTDIR"
WriteUninstaller "$INSTDIR\uninstall.exe"
!ifdef REG_START_MENU
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
CreateDirectory "$SMPROGRAMS\$SM_Folder"
CreateShortCut "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
CreateShortCut "$SMPROGRAMS\$SM_Folder\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
!ifdef WEB_SITE
WriteIniStr "$INSTDIR\UltiMaker Cura website.url" "InternetShortcut" "URL" "${WEB_SITE}"
CreateShortCut "$SMPROGRAMS\$SM_Folder\UltiMaker Cura website.lnk" "$INSTDIR\UltiMaker Cura website.url"
!endif
!insertmacro MUI_STARTMENU_WRITE_END
CreateShortCut "$SMPROGRAMS\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
!endif
!ifndef REG_START_MENU
CreateDirectory "$SMPROGRAMS\{{ app_name }}"
CreateShortCut "$SMPROGRAMS\{{ app_name }}\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
CreateShortCut "$SMPROGRAMS\{{ app_name }}\Uninstall ${APP_NAME}.lnk" "$INSTDIR\uninstall.exe"
!ifdef WEB_SITE
WriteIniStr "$INSTDIR\UltiMaker Cura website.url" "InternetShortcut" "URL" "${WEB_SITE}"
CreateShortCut "$SMPROGRAMS\{{ app_name }}\UltiMaker Cura website.lnk" "$INSTDIR\UltiMaker Cura website.url"
!endif
CreateShortCut "$SMPROGRAMS\${APP_NAME}.lnk" "$INSTDIR\${MAIN_APP_EXE}"
!endif
WriteRegStr ${REG_ROOT} "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
@ -138,9 +117,6 @@ WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayIcon" "$INSTDIR\${MAIN_APP_
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "${VERSION}"
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "${COMP_NAME}"
!ifdef WEB_SITE
WriteRegStr ${REG_ROOT} "${UNINSTALL_PATH}" "URLInfoAbout" "${WEB_SITE}"
!endif
SectionEnd
######################################################################
@ -177,29 +153,17 @@ RmDir "$INSTDIR\share\uranium"
RmDir "$INSTDIR\share"
Delete "$INSTDIR\uninstall.exe"
!ifdef WEB_SITE
Delete "$INSTDIR\${APP_NAME} website.url"
!endif
RmDir /r /REBOOTOK "$INSTDIR"
!ifdef REG_START_MENU
!insertmacro MUI_STARTMENU_GETFOLDER "Application" $SM_Folder
Delete "$SMPROGRAMS\$SM_Folder\${APP_NAME}.lnk"
Delete "$SMPROGRAMS\$SM_Folder\Uninstall ${APP_NAME}.lnk"
!ifdef WEB_SITE
Delete "$SMPROGRAMS\$SM_Folder\UltiMaker Cura website.lnk"
!endif
RmDir "$SMPROGRAMS\$SM_Folder"
Delete "$SMPROGRAMS\${APP_NAME}.lnk"
Delete "$SMPROGRAMS\Uninstall ${APP_NAME}.lnk"
!endif
!ifndef REG_START_MENU
Delete "$SMPROGRAMS\{{ app_name }}\${APP_NAME}.lnk"
Delete "$SMPROGRAMS\{{ app_name }}\Uninstall ${APP_NAME}.lnk"
!ifdef WEB_SITE
Delete "$SMPROGRAMS\{{ app_name }}\UltiMaker Cura website.lnk"
!endif
RmDir "$SMPROGRAMS\{{ app_name }}"
Delete "$SMPROGRAMS\${APP_NAME}.lnk"
Delete "$SMPROGRAMS\Uninstall ${APP_NAME}.lnk"
!endif
!insertmacro APP_UNASSOCIATE "stl" "Cura.model"

View file

@ -1,4 +1,4 @@
# Copyright (c) 2022 UltiMaker
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
@ -51,7 +51,6 @@ def generate_nsi(source_path: str, dist_path: str, filename: str, version: str):
version_minor = str(parsed_version.minor),
version_patch = str(parsed_version.patch),
company = "UltiMaker",
web_site = "https://ultimaker.com",
year = datetime.now().year,
cura_license_file = str(source_loc.joinpath("packaging", "cura_license.txt")),
compression_method = "LZMA", # ZLIB, BZIP2 or LZMA

View file

@ -1,4 +1,4 @@
# Copyright (c) 2022 UltiMaker
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
@ -40,7 +40,6 @@ def generate_wxs(source_path: Path, dist_path: Path, filename: Path, app_name: s
version_minor=str(parsed_version.minor),
version_patch=str(parsed_version.patch),
company="UltiMaker",
web_site="https://ultimaker.com",
year=datetime.now().year,
upgrade_code=str(uuid.uuid5(uuid.NAMESPACE_DNS, app_name)),
cura_license_file=str(source_loc.joinpath("packaging", "msi", "cura_license.rtf")),

View file

@ -94,7 +94,7 @@ class ThreeMFReader(MeshReader):
return temp_mat
@staticmethod
def _convertSavitarNodeToUMNode(savitar_node: Savitar.SceneNode, file_name: str = "") -> Optional[SceneNode]:
def _convertSavitarNodeToUMNode(savitar_node: Savitar.SceneNode, file_name: str = "", archive: zipfile.ZipFile = None) -> Optional[SceneNode]:
"""Convenience function that converts a SceneNode object (as obtained from libSavitar) to a scene node.
:returns: Scene node.
@ -115,6 +115,10 @@ class ThreeMFReader(MeshReader):
active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate
component_path = savitar_node.getComponentPath()
if component_path != "" and archive is not None:
savitar_node.parseComponentData(archive.open(component_path.lstrip("/")).read())
um_node = CuraSceneNode() # This adds a SettingOverrideDecorator
um_node.addDecorator(BuildPlateDecorator(active_build_plate))
try:
@ -143,7 +147,7 @@ class ThreeMFReader(MeshReader):
um_node.setMeshData(mesh_data)
for child in savitar_node.getChildren():
child_node = ThreeMFReader._convertSavitarNodeToUMNode(child)
child_node = ThreeMFReader._convertSavitarNodeToUMNode(child, archive=archive)
if child_node:
um_node.addChild(child_node)
@ -232,7 +236,7 @@ class ThreeMFReader(MeshReader):
CuraApplication.getInstance().getController().getScene().setMetaDataEntry(key, value)
for node in scene_3mf.getSceneNodes():
um_node = ThreeMFReader._convertSavitarNodeToUMNode(node, file_name)
um_node = ThreeMFReader._convertSavitarNodeToUMNode(node, file_name, archive)
if um_node is None:
continue

View file

@ -23,7 +23,7 @@ def getMetaData() -> Dict:
if "3MFReader.ThreeMFReader" in sys.modules:
metaData["mesh_reader"] = [
{
"extension": "3mf",
"extension": workspace_extension,
"description": catalog.i18nc("@item:inlistbox", "3MF File")
}
]

View file

@ -0,0 +1,176 @@
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import hashlib
import json
from io import StringIO
import xml.etree.ElementTree as ET
import zipfile
from PyQt6.QtCore import Qt, QBuffer
from PyQt6.QtGui import QImage
from UM.Application import Application
from UM.Logger import Logger
from UM.Mesh.MeshWriter import MeshWriter
from UM.PluginRegistry import PluginRegistry
from typing import cast
from cura.CuraApplication import CuraApplication
from .ThreeMFVariant import ThreeMFVariant
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
# Path constants
METADATA_PATH = "Metadata"
THUMBNAIL_PATH_MULTIPLATE = f"{METADATA_PATH}/plate_1.png"
THUMBNAIL_PATH_MULTIPLATE_SMALL = f"{METADATA_PATH}/plate_1_small.png"
GCODE_PATH = f"{METADATA_PATH}/plate_1.gcode"
GCODE_MD5_PATH = f"{GCODE_PATH}.md5"
MODEL_SETTINGS_PATH = f"{METADATA_PATH}/model_settings.config"
PLATE_DESC_PATH = f"{METADATA_PATH}/plate_1.json"
SLICE_INFO_PATH = f"{METADATA_PATH}/slice_info.config"
PROJECT_SETTINGS_PATH = f"{METADATA_PATH}/project_settings.config"
class BambuLabVariant(ThreeMFVariant):
"""BambuLab specific implementation of the 3MF format."""
@property
def mime_type(self) -> str:
return "application/vnd.bambulab-package.3dmanufacturing-3dmodel+xml"
def process_thumbnail(self, snapshot: QImage, thumbnail_buffer: QBuffer,
archive: zipfile.ZipFile, relations_element: ET.Element) -> None:
"""Process the thumbnail for BambuLab variant."""
# Write thumbnail
archive.writestr(zipfile.ZipInfo(THUMBNAIL_PATH_MULTIPLATE), thumbnail_buffer.data())
# Add relations elements for thumbnails
ET.SubElement(relations_element, "Relationship",
Target="/" + THUMBNAIL_PATH_MULTIPLATE, Id="rel-2",
pe="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail")
ET.SubElement(relations_element, "Relationship",
Target="/" + THUMBNAIL_PATH_MULTIPLATE, Id="rel-4",
Type="http://schemas.bambulab.com/package/2021/cover-thumbnail-middle")
# Create and save small thumbnail
small_snapshot = snapshot.scaled(128, 128, transformMode=Qt.TransformationMode.SmoothTransformation)
small_thumbnail_buffer = QBuffer()
small_thumbnail_buffer.open(QBuffer.OpenModeFlag.ReadWrite)
small_snapshot.save(small_thumbnail_buffer, "PNG")
# Write small thumbnail
archive.writestr(zipfile.ZipInfo(THUMBNAIL_PATH_MULTIPLATE_SMALL), small_thumbnail_buffer.data())
# Add relation for small thumbnail
ET.SubElement(relations_element, "Relationship",
Target="/" + THUMBNAIL_PATH_MULTIPLATE_SMALL, Id="rel-5",
Type="http://schemas.bambulab.com/package/2021/cover-thumbnail-small")
def add_extra_files(self, archive: zipfile.ZipFile, metadata_relations_element: ET.Element) -> None:
"""Add BambuLab specific files to the archive."""
self._storeGCode(archive, metadata_relations_element)
self._storeModelSettings(archive)
self._storePlateDesc(archive)
self._storeSliceInfo(archive)
self._storeProjectSettings(archive)
def _storeGCode(self, archive: zipfile.ZipFile, metadata_relations_element: ET.Element):
"""Store GCode data in the archive."""
gcode_textio = StringIO()
gcode_writer = cast(MeshWriter, PluginRegistry.getInstance().getPluginObject("GCodeWriter"))
success = gcode_writer.write(gcode_textio, None)
if not success:
error_msg = catalog.i18nc("@info:error", "Can't write GCode to 3MF file")
self._writer.setInformation(error_msg)
Logger.error(error_msg)
raise Exception(error_msg)
gcode_data = gcode_textio.getvalue().encode("UTF-8")
archive.writestr(zipfile.ZipInfo(GCODE_PATH), gcode_data)
gcode_relation_element = ET.SubElement(metadata_relations_element, "Relationship",
Target=f"/{GCODE_PATH}", Id="rel-1",
Type="http://schemas.bambulab.com/package/2021/gcode")
# Calculate and store the MD5 sum of the gcode data
md5_hash = hashlib.md5(gcode_data).hexdigest()
archive.writestr(zipfile.ZipInfo(GCODE_MD5_PATH), md5_hash.encode("UTF-8"))
def _storeModelSettings(self, archive: zipfile.ZipFile):
"""Store model settings in the archive."""
config = ET.Element("config")
plate = ET.SubElement(config, "plate")
ET.SubElement(plate, "metadata", key="plater_id", value="1")
ET.SubElement(plate, "metadata", key="plater_name", value="")
ET.SubElement(plate, "metadata", key="locked", value="false")
ET.SubElement(plate, "metadata", key="filament_map_mode", value="Auto For Flush")
extruders_count = len(CuraApplication.getInstance().getExtruderManager().extruderIds)
ET.SubElement(plate, "metadata", key="filament_maps", value=" ".join("1" for _ in range(extruders_count)))
ET.SubElement(plate, "metadata", key="gcode_file", value=GCODE_PATH)
ET.SubElement(plate, "metadata", key="thumbnail_file", value=THUMBNAIL_PATH_MULTIPLATE)
ET.SubElement(plate, "metadata", key="pattern_bbox_file", value=PLATE_DESC_PATH)
self._writer._storeElementTree(archive, MODEL_SETTINGS_PATH, config)
def _storePlateDesc(self, archive: zipfile.ZipFile):
"""Store plate description in the archive."""
plate_desc = {}
filament_ids = []
filament_colors = []
for extruder in CuraApplication.getInstance().getExtruderManager().getUsedExtruderStacks():
filament_ids.append(extruder.getValue("extruder_nr"))
filament_colors.append(self._writer._getMaterialColor(extruder))
plate_desc["filament_ids"] = filament_ids
plate_desc["filament_colors"] = filament_colors
plate_desc["first_extruder"] = CuraApplication.getInstance().getExtruderManager().getInitialExtruderNr()
plate_desc["is_seq_print"] = Application.getInstance().getGlobalContainerStack().getValue("print_sequence") == "one_at_a_time"
plate_desc["nozzle_diameter"] = CuraApplication.getInstance().getExtruderManager().getActiveExtruderStack().getValue("machine_nozzle_size")
plate_desc["version"] = 2
file = zipfile.ZipInfo(PLATE_DESC_PATH)
file.compress_type = zipfile.ZIP_DEFLATED
archive.writestr(file, json.dumps(plate_desc).encode("UTF-8"))
def _storeSliceInfo(self, archive: zipfile.ZipFile):
"""Store slice information in the archive."""
config = ET.Element("config")
header = ET.SubElement(config, "header")
ET.SubElement(header, "header_item", key="X-BBL-Client-Type", value="slicer")
ET.SubElement(header, "header_item", key="X-BBL-Client-Version", value="02.00.01.50")
plate = ET.SubElement(config, "plate")
ET.SubElement(plate, "metadata", key="index", value="1")
ET.SubElement(plate,
"metadata",
key="nozzle_diameters",
value=str(CuraApplication.getInstance().getExtruderManager().getActiveExtruderStack().getValue("machine_nozzle_size")))
print_information = CuraApplication.getInstance().getPrintInformation()
for index, extruder in enumerate(Application.getInstance().getGlobalContainerStack().extruderList):
used_m = print_information.materialLengths[index]
used_g = print_information.materialWeights[index]
if used_m > 0.0 and used_g > 0.0:
ET.SubElement(plate,
"filament",
id=str(extruder.getValue("extruder_nr") + 1),
tray_info_idx="GFA00",
type=extruder.material.getMetaDataEntry("material", ""),
color=self._writer._getMaterialColor(extruder),
used_m=str(used_m),
used_g=str(used_g))
self._writer._storeElementTree(archive, SLICE_INFO_PATH, config)
def _storeProjectSettings(self, archive: zipfile.ZipFile):
api = CuraApplication.getInstance().getCuraAPI()
file = zipfile.ZipInfo(PROJECT_SETTINGS_PATH)
json_string = json.dumps(api.interface.settings.getAllGlobalSettings(), separators=(", ", ": "), indent=4)
archive.writestr(file, json_string.encode("UTF-8"))

View file

@ -0,0 +1,33 @@
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import xml.etree.ElementTree as ET
import zipfile
from PyQt6.QtCore import QBuffer
from PyQt6.QtGui import QImage
from .ThreeMFVariant import ThreeMFVariant
# Standard 3MF paths
METADATA_PATH = "Metadata"
THUMBNAIL_PATH = f"{METADATA_PATH}/thumbnail.png"
class Cura3mfVariant(ThreeMFVariant):
"""Default implementation of the 3MF format."""
@property
def mime_type(self) -> str:
return "application/vnd.ms-package.3dmanufacturing-3dmodel+xml"
def process_thumbnail(self, snapshot: QImage, thumbnail_buffer: QBuffer,
archive: zipfile.ZipFile, relations_element: ET.Element) -> None:
"""Process the thumbnail for default 3MF variant."""
thumbnail_file = zipfile.ZipInfo(THUMBNAIL_PATH)
# Don't try to compress snapshot file, because the PNG is pretty much as compact as it will get
archive.writestr(thumbnail_file, thumbnail_buffer.data())
# Add thumbnail relation to _rels/.rels file
ET.SubElement(relations_element, "Relationship",
Target="/" + THUMBNAIL_PATH, Id="rel1",
Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail")

View file

@ -0,0 +1,74 @@
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING
import xml.etree.ElementTree as ET
import zipfile
from PyQt6.QtGui import QImage
from PyQt6.QtCore import QBuffer
if TYPE_CHECKING:
from .ThreeMFWriter import ThreeMFWriter
class ThreeMFVariant(ABC):
"""Base class for 3MF format variants.
Different vendors may have their own extensions to the 3MF format,
such as BambuLab's 3MF variant. This class provides an interface
for implementing these variants.
"""
def __init__(self, writer: 'ThreeMFWriter'):
"""
:param writer: The ThreeMFWriter instance that will use this variant
"""
self._writer = writer
@property
@abstractmethod
def mime_type(self) -> str:
"""The MIME type for this 3MF variant."""
pass
def handles_mime_type(self, mime_type: str) -> bool:
"""Check if this variant handles the given MIME type.
:param mime_type: The MIME type to check
:return: True if this variant handles the MIME type, False otherwise
"""
return mime_type == self.mime_type
def prepare_content_types(self, content_types: ET.Element) -> None:
"""Prepare the content types XML element for this variant.
:param content_types: The content types XML element
"""
pass
def prepare_relations(self, relations_element: ET.Element) -> None:
"""Prepare the relations XML element for this variant.
:param relations_element: The relations XML element
"""
pass
def process_thumbnail(self, snapshot: QImage, thumbnail_buffer: QBuffer,
archive: zipfile.ZipFile, relations_element: ET.Element) -> None:
"""Process the thumbnail for this variant.
:param snapshot: The snapshot image
:param thumbnail_buffer: Buffer containing the thumbnail data
:param archive: The zip archive to write to
:param relations_element: The relations XML element
"""
pass
def add_extra_files(self, archive: zipfile.ZipFile, metadata_relations_element: ET.Element) -> None:
"""Add any extra files required by this variant to the archive.
:param archive: The zip archive to write to
:param metadata_relations_element: The metadata relations XML element
"""
pass

View file

@ -1,11 +1,13 @@
# Copyright (c) 2015-2022 Ultimaker B.V.
# Copyright (c) 2015-2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import json
import re
import threading
from typing import Optional, cast, List, Dict, Pattern, Set
from typing import Optional, cast, List, Dict, Set
from UM.PluginRegistry import PluginRegistry
from UM.Mesh.MeshWriter import MeshWriter
from UM.Math.Vector import Vector
from UM.Logger import Logger
@ -19,7 +21,9 @@ from UM.Settings.ContainerRegistry import ContainerRegistry
from cura.CuraApplication import CuraApplication
from cura.CuraPackageManager import CuraPackageManager
from cura.Machines.Models.ExtrudersModel import ExtrudersModel
from cura.Settings import CuraContainerStack
from cura.Settings.ExtruderStack import ExtruderStack
from cura.Utils.Threading import call_on_qt_thread
from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.Snapshot import Snapshot
@ -45,11 +49,13 @@ import UM.Application
from .SettingsExportModel import SettingsExportModel
from .SettingsExportGroup import SettingsExportGroup
from .ThreeMFVariant import ThreeMFVariant
from .Cura3mfVariant import Cura3mfVariant
from .BambuLabVariant import BambuLabVariant
from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura")
THUMBNAIL_PATH = "Metadata/thumbnail.png"
MODEL_PATH = "3D/3dmodel.model"
PACKAGE_METADATA_PATH = "Cura/packages.json"
@ -68,6 +74,12 @@ class ThreeMFWriter(MeshWriter):
self._store_archive = False
self._lock = threading.Lock()
# Register available variants
self._variants = {
Cura3mfVariant(self).mime_type: Cura3mfVariant,
BambuLabVariant(self).mime_type: BambuLabVariant
}
@staticmethod
def _convertMatrixToString(matrix):
result = ""
@ -201,26 +213,48 @@ class ThreeMFWriter(MeshWriter):
painter.end()
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode, export_settings_model = None) -> bool:
def _getVariant(self, mime_type: str) -> ThreeMFVariant:
"""Get the appropriate variant for the given MIME type.
:param mime_type: The MIME type to get the variant for
:return: An instance of the variant for the given MIME type
"""
variant_class = self._variants.get(mime_type, Cura3mfVariant)
return variant_class(self)
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode, export_settings_model = None, **kwargs) -> bool:
self._archive = None # Reset archive
archive = zipfile.ZipFile(stream, "w", compression = zipfile.ZIP_DEFLATED)
# Determine which variant to use based on mime type in kwargs
mime_type = kwargs.get("mime_type", Cura3mfVariant(self).mime_type)
variant = self._getVariant(mime_type)
try:
model_file = zipfile.ZipInfo(MODEL_PATH)
# Because zipfile is stupid and ignores archive-level compression settings when writing with ZipInfo.
model_file.compress_type = zipfile.ZIP_DEFLATED
# Create content types file
content_types_file = zipfile.ZipInfo("[Content_Types].xml")
content_types_file.compress_type = zipfile.ZIP_DEFLATED
content_types = ET.Element("Types", xmlns = self._namespaces["content-types"])
rels_type = ET.SubElement(content_types, "Default", Extension = "rels", ContentType = "application/vnd.openxmlformats-package.relationships+xml")
model_type = ET.SubElement(content_types, "Default", Extension = "model", ContentType = "application/vnd.ms-package.3dmanufacturing-3dmodel+xml")
# Create _rels/.rels file
relations_file = zipfile.ZipInfo("_rels/.rels")
relations_file.compress_type = zipfile.ZIP_DEFLATED
relations_element = ET.Element("Relationships", xmlns = self._namespaces["relationships"])
model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/" + MODEL_PATH, Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel")
relations_element = self._makeRelationsTree()
model_relation_element = ET.SubElement(relations_element, "Relationship", Target="/" + MODEL_PATH,
Id="rel0",
Type="http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel")
# Create Metadata/_rels/model_settings.config.rels
metadata_relations_element = self._makeRelationsTree()
# Let the variant add its specific files
variant.add_extra_files(archive, metadata_relations_element)
# Let the variant prepare content types and relations
variant.prepare_content_types(content_types)
variant.prepare_relations(relations_element)
# Attempt to add a thumbnail
snapshot = self._createSnapshot()
@ -233,16 +267,11 @@ class ThreeMFWriter(MeshWriter):
thumbnail_buffer.open(QBuffer.OpenModeFlag.ReadWrite)
snapshot.save(thumbnail_buffer, "PNG")
thumbnail_file = zipfile.ZipInfo(THUMBNAIL_PATH)
# Don't try to compress snapshot file, because the PNG is pretty much as compact as it will get
archive.writestr(thumbnail_file, thumbnail_buffer.data())
# Add PNG to content types file
thumbnail_type = ET.SubElement(content_types, "Default", Extension="png", ContentType="image/png")
# Add thumbnail relation to _rels/.rels file
thumbnail_relation_element = ET.SubElement(relations_element, "Relationship",
Target="/" + THUMBNAIL_PATH, Id="rel1",
Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail")
# Let the variant process the thumbnail
variant.process_thumbnail(snapshot, thumbnail_buffer, archive, relations_element)
# Write material metadata
packages_metadata = self._getMaterialPackageMetadata() + self._getPluginPackageMetadata()
@ -305,8 +334,10 @@ class ThreeMFWriter(MeshWriter):
scene_string = parser.sceneToString(savitar_scene)
archive.writestr(model_file, scene_string)
archive.writestr(content_types_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(content_types))
archive.writestr(relations_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(relations_element))
self._storeElementTree(archive, "[Content_Types].xml", content_types)
self._storeElementTree(archive, "_rels/.rels", relations_element)
if len(metadata_relations_element) > 0:
self._storeElementTree(archive, "Metadata/_rels/model_settings.config.rels", metadata_relations_element)
except Exception as error:
Logger.logException("e", "Error writing zip file")
self.setInformation(str(error))
@ -319,6 +350,25 @@ class ThreeMFWriter(MeshWriter):
return True
@staticmethod
def _storeElementTree(archive: zipfile.ZipFile, file_path: str, root_element: ET.Element):
file = zipfile.ZipInfo(file_path)
file.compress_type = zipfile.ZIP_DEFLATED
archive.writestr(file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(root_element))
def _makeRelationsTree(self):
return ET.Element("Relationships", xmlns=self._namespaces["relationships"])
@staticmethod
def _getMaterialColor(extruder: "ExtruderStack") -> str:
position = int(extruder.getMetaDataEntry("position", default="0"))
try:
default_color = ExtrudersModel.defaultColors[position]
except IndexError:
default_color = "#e0e000"
color_code = extruder.material.getMetaDataEntry("color_code", default=default_color)
return color_code.upper()
@staticmethod
def _storeMetadataJson(metadata: Dict[str, List[Dict[str, str]]], archive: zipfile.ZipFile, path: str) -> None:
"""Stores metadata inside archive path as json file"""

View file

@ -28,11 +28,17 @@ def getMetaData():
metaData["mesh_writer"] = {
"output": [
{
"extension": "3mf",
"extension": workspace_extension,
"description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"),
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode
},
{
"extension": f"gcode.{workspace_extension}",
"description": i18n_catalog.i18nc("@item:inlistbox", "BambuLab 3MF file"),
"mime_type": "application/vnd.bambulab-package.3dmanufacturing-3dmodel+xml",
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
}
]
}
metaData["workspace_writer"] = {
@ -44,7 +50,7 @@ def getMetaData():
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
},
{
"extension": "3mf",
"extension": workspace_extension,
"description": i18n_catalog.i18nc("@item:inlistbox", "Universal Cura Project"),
"mime_type": "application/x-ucp",
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode

View file

@ -1,4 +1,4 @@
# Copyright (c) 2020 Ultimaker B.V.
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import json
import threading
@ -13,11 +13,14 @@ from UM.Message import Message
from UM.TaskManagement.HttpRequestManager import HttpRequestManager
from UM.TaskManagement.HttpRequestScope import JsonDecoratorScope
from UM.i18n import i18nCatalog
from cura.ApplicationMetadata import CuraSDKVersion
from cura.CuraApplication import CuraApplication
from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope
import cura.UltimakerCloud.UltimakerCloudConstants as UltimakerCloudConstants
catalog = i18nCatalog("cura")
PACKAGES_URL = f"{UltimakerCloudConstants.CuraCloudAPIRoot}/cura-packages/v{UltimakerCloudConstants.CuraCloudAPIVersion}/cura/v{CuraSDKVersion}/packages"
class CreateBackupJob(Job):
"""Creates backup zip, requests upload url and uploads the backup file to cloud storage."""
@ -40,23 +43,54 @@ class CreateBackupJob(Job):
self._job_done = threading.Event()
"""Set when the job completes. Does not indicate success."""
self.backup_upload_error_message = ""
"""After the job completes, an empty string indicates success. Othrerwise, the value is a translated message."""
"""After the job completes, an empty string indicates success. Otherwise, the value is a translated message."""
def _setPluginFetchErrorMessage(self, error_msg: str) -> None:
Logger.error(f"Fetching plugins for backup resulted in error: {error_msg}")
self.backup_upload_error_message = "Couldn't update currently available plugins, backup stopped."
self._upload_message.hide()
self._job_done.set()
def run(self) -> None:
upload_message = Message(catalog.i18nc("@info:backup_status", "Creating your backup..."),
self._upload_message = Message(catalog.i18nc("@info:backup_status", "Fetch re-downloadable package-ids..."),
title = self.MESSAGE_TITLE,
progress = -1)
upload_message.show()
self._upload_message.show()
CuraApplication.getInstance().processEvents()
if CuraApplication.getInstance().getCuraAPI().backups.shouldReinstallDownloadablePlugins():
request_url = f"{PACKAGES_URL}?package_type=plugin"
scope = JsonDecoratorScope(UltimakerCloudScope(CuraApplication.getInstance()))
HttpRequestManager.getInstance().get(
request_url,
scope=scope,
callback=self._continueRun,
error_callback=lambda reply, error: self._setPluginFetchErrorMessage(str(error)),
)
else:
self._continueRun()
def _continueRun(self, reply: "QNetworkReply" = None) -> None:
if reply is not None:
response_data = HttpRequestManager.readJSON(reply)
if "data" not in response_data:
self._setPluginFetchErrorMessage(f"Missing 'data' from response. Keys in response: {response_data.keys()}")
return
available_remote_plugins = frozenset({v["package_id"] for v in response_data["data"]})
else:
available_remote_plugins = frozenset()
self._upload_message.setText(catalog.i18nc("@info:backup_status", "Creating your backup..."))
CuraApplication.getInstance().processEvents()
cura_api = CuraApplication.getInstance().getCuraAPI()
self._backup_zip, backup_meta_data = cura_api.backups.createBackup()
self._backup_zip, backup_meta_data = cura_api.backups.createBackup(available_remote_plugins)
if not self._backup_zip or not backup_meta_data:
self.backup_upload_error_message = catalog.i18nc("@info:backup_status", "There was an error while creating your backup.")
upload_message.hide()
self._upload_message.hide()
return
upload_message.setText(catalog.i18nc("@info:backup_status", "Uploading your backup..."))
self._upload_message.setText(catalog.i18nc("@info:backup_status", "Uploading your backup..."))
CuraApplication.getInstance().processEvents()
# Create an upload entry for the backup.
@ -64,13 +98,18 @@ class CreateBackupJob(Job):
backup_meta_data["description"] = "{}.backup.{}.cura.zip".format(timestamp, backup_meta_data["cura_release"])
self._requestUploadSlot(backup_meta_data, len(self._backup_zip))
self._job_done.wait()
# Note: One 'process events' call wasn't enough with the changed situation somehow.
for _ in range(5000):
CuraApplication.getInstance().processEvents()
if self._job_done.wait(0.02):
break
if self.backup_upload_error_message == "":
upload_message.setText(catalog.i18nc("@info:backup_status", "Your backup has finished uploading."))
upload_message.setProgress(None) # Hide progress bar
self._upload_message.setText(catalog.i18nc("@info:backup_status", "Your backup has finished uploading."))
self._upload_message.setProgress(None) # Hide progress bar
else:
# some error occurred. This error is presented to the user by DrivePluginExtension
upload_message.hide()
self._upload_message.hide()
def _requestUploadSlot(self, backup_metadata: Dict[str, Any], backup_size: int) -> None:
"""Request a backup upload slot from the API.
@ -83,7 +122,6 @@ class CreateBackupJob(Job):
"metadata": backup_metadata
}
}).encode()
HttpRequestManager.getInstance().put(
self._api_backup_url,
data = payload,

View file

@ -1,8 +1,9 @@
# Copyright (c) 2021 Ultimaker B.V.
# Copyright (c) 2025 UltiMaker
# Cura is released under the terms of the LGPLv3 or higher.
import base64
import hashlib
import json
import os
import threading
from tempfile import NamedTemporaryFile
from typing import Optional, Any, Dict
@ -12,9 +13,16 @@ from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
from UM.Job import Job
from UM.Logger import Logger
from UM.PackageManager import catalog
from UM.Resources import Resources
from UM.TaskManagement.HttpRequestManager import HttpRequestManager
from cura.CuraApplication import CuraApplication
from UM.Version import Version
from cura.ApplicationMetadata import CuraSDKVersion
from cura.CuraApplication import CuraApplication
from cura.UltimakerCloud.UltimakerCloudScope import UltimakerCloudScope
import cura.UltimakerCloud.UltimakerCloudConstants as UltimakerCloudConstants
PACKAGES_URL_TEMPLATE = f"{UltimakerCloudConstants.CuraCloudAPIRoot}/cura-packages/v{UltimakerCloudConstants.CuraCloudAPIVersion}/cura/v{{0}}/packages/{{1}}/download"
class RestoreBackupJob(Job):
"""Downloads a backup and overwrites local configuration with the backup.
@ -38,7 +46,6 @@ class RestoreBackupJob(Job):
self.restore_backup_error_message = ""
def run(self) -> None:
url = self._backup.get("download_url")
assert url is not None
@ -48,7 +55,11 @@ class RestoreBackupJob(Job):
error_callback = self._onRestoreRequestCompleted
)
self._job_done.wait() # A job is considered finished when the run function completes
# Note: Just to be sure, use the same structure here as in CreateBackupJob.
for _ in range(5000):
CuraApplication.getInstance().processEvents()
if self._job_done.wait(0.02):
break
def _onRestoreRequestCompleted(self, reply: QNetworkReply, error: Optional["QNetworkReply.NetworkError"] = None) -> None:
if not HttpRequestManager.replyIndicatesSuccess(reply, error):
@ -60,8 +71,8 @@ class RestoreBackupJob(Job):
# We store the file in a temporary path fist to ensure integrity.
try:
temporary_backup_file = NamedTemporaryFile(delete = False)
with open(temporary_backup_file.name, "wb") as write_backup:
self._temporary_backup_file = NamedTemporaryFile(delete_on_close = False)
with open(self._temporary_backup_file.name, "wb") as write_backup:
app = CuraApplication.getInstance()
bytes_read = reply.read(self.DISK_WRITE_BUFFER_SIZE)
while bytes_read:
@ -69,23 +80,98 @@ class RestoreBackupJob(Job):
bytes_read = reply.read(self.DISK_WRITE_BUFFER_SIZE)
app.processEvents()
except EnvironmentError as e:
Logger.log("e", f"Unable to save backed up files due to computer limitations: {str(e)}")
Logger.error(f"Unable to save backed up files due to computer limitations: {str(e)}")
self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE
self._job_done.set()
return
if not self._verifyMd5Hash(temporary_backup_file.name, self._backup.get("md5_hash", "")):
if not self._verifyMd5Hash(self._temporary_backup_file.name, self._backup.get("md5_hash", "")):
# Don't restore the backup if the MD5 hashes do not match.
# This can happen if the download was interrupted.
Logger.log("w", "Remote and local MD5 hashes do not match, not restoring backup.")
Logger.error("Remote and local MD5 hashes do not match, not restoring backup.")
self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE
self._job_done.set()
return
# Tell Cura to place the backup back in the user data folder.
with open(temporary_backup_file.name, "rb") as read_backup:
metadata = self._backup.get("metadata", {})
with open(self._temporary_backup_file.name, "rb") as read_backup:
cura_api = CuraApplication.getInstance().getCuraAPI()
cura_api.backups.restoreBackup(read_backup.read(), self._backup.get("metadata", {}))
cura_api.backups.restoreBackup(read_backup.read(), metadata, auto_close=False)
self._job_done.set()
# Read packages data-file, to get the 'to_install' plugin-ids.
version_to_restore = Version(metadata.get("cura_release", "dev"))
version_str = f"{version_to_restore.getMajor()}.{version_to_restore.getMinor()}"
packages_path = os.path.abspath(os.path.join(os.path.abspath(
Resources.getConfigStoragePath()), "..", version_str, "packages.json"))
if not os.path.exists(packages_path):
Logger.error(f"Can't find path '{packages_path}' to tell what packages should be redownloaded.")
self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE
self._job_done.set()
return
to_install = {}
try:
with open(packages_path, "r") as packages_file:
packages_json = json.load(packages_file)
if "to_install" in packages_json:
for package_data in packages_json["to_install"].values():
if "package_info" not in package_data:
continue
package_info = package_data["package_info"]
if "package_id" in package_info and "sdk_version_semver" in package_info:
to_install[package_info["package_id"]] = package_info["sdk_version_semver"]
except IOError as ex:
Logger.error(f"Couldn't open '{packages_path}' because '{str(ex)}' to get packages to re-install.")
self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE
self._job_done.set()
return
if len(to_install) < 1:
Logger.info("No packages to reinstall, early out.")
self._job_done.set()
return
# Download all re-installable plugins packages, so they can be put back on start-up.
redownload_errors = []
def packageDownloadCallback(package_id: str, msg: "QNetworkReply", err: "QNetworkReply.NetworkError" = None) -> None:
if err is not None or HttpRequestManager.safeHttpStatus(msg) != 200:
redownload_errors.append(err)
del to_install[package_id]
try:
with NamedTemporaryFile(mode="wb", suffix=".curapackage", delete=False) as temp_file:
bytes_read = msg.read(self.DISK_WRITE_BUFFER_SIZE)
while bytes_read:
temp_file.write(bytes_read)
bytes_read = msg.read(self.DISK_WRITE_BUFFER_SIZE)
CuraApplication.getInstance().processEvents()
temp_file.close()
if not CuraApplication.getInstance().getPackageManager().installPackage(temp_file.name):
redownload_errors.append(f"Couldn't install package '{package_id}'.")
except IOError as ex:
redownload_errors.append(f"Couldn't process package '{package_id}' because '{ex}'.")
if len(to_install) < 1:
if len(redownload_errors) == 0:
Logger.info("All packages redownloaded!")
self._job_done.set()
else:
msgs = "\n - ".join(redownload_errors)
Logger.error(f"Couldn't re-install at least one package(s) because: {msgs}")
self.restore_backup_error_message = self.DEFAULT_ERROR_MESSAGE
self._job_done.set()
self._package_download_scope = UltimakerCloudScope(CuraApplication.getInstance())
for package_id, package_api_version in to_install.items():
def handlePackageId(package_id: str = package_id):
HttpRequestManager.getInstance().get(
PACKAGES_URL_TEMPLATE.format(package_api_version, package_id),
scope=self._package_download_scope,
callback=lambda msg: packageDownloadCallback(package_id, msg),
error_callback=lambda msg, err: packageDownloadCallback(package_id, msg, err)
)
handlePackageId(package_id)
@staticmethod
def _verifyMd5Hash(file_path: str, known_hash: str) -> bool:

View file

@ -24,7 +24,7 @@ class GCodeGzWriter(MeshWriter):
def __init__(self) -> None:
super().__init__(add_to_recent_files = False)
def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode = MeshWriter.OutputMode.BinaryMode) -> bool:
def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode = MeshWriter.OutputMode.BinaryMode, **kwargs) -> bool:
"""Writes the gzipped g-code to a stream.
Note that even though the function accepts a collection of nodes, the

View file

@ -56,7 +56,7 @@ class GCodeWriter(MeshWriter):
self._application = Application.getInstance()
def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode):
def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode, **kwargs):
"""Writes the g-code for the entire scene to a stream.
Note that even though the function accepts a collection of nodes, the

View file

@ -91,7 +91,7 @@ class MakerbotWriter(MeshWriter):
return None
def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode=MeshWriter.OutputMode.BinaryMode) -> bool:
def write(self, stream: BufferedIOBase, nodes: List[SceneNode], mode=MeshWriter.OutputMode.BinaryMode, **kwargs) -> bool:
metadata, file_format = self._getMeta(nodes)
if mode != MeshWriter.OutputMode.BinaryMode:
Logger.log("e", "MakerbotWriter does not support text mode.")
@ -258,11 +258,87 @@ class MakerbotWriter(MeshWriter):
meta["preferences"] = dict()
bounds = application.getBuildVolume().getBoundingBox()
intent = CuraApplication.getInstance().getIntentManager().currentIntentCategory
meta["preferences"]["instance0"] = {
"machineBounds": [bounds.right, bounds.front, bounds.left, bounds.back] if bounds is not None else None,
"printMode": CuraApplication.getInstance().getIntentManager().currentIntentCategory,
"printMode": intent
}
if file_format == "application/x-makerbot":
accel_overrides = meta["accel_overrides"] = {}
if intent in ['highspeed', 'highspeedsolid']:
accel_overrides['do_input_shaping'] = True
accel_overrides['do_corner_rounding'] = True
bead_mode_overrides = accel_overrides["bead_mode"] = {}
accel_enabled = global_stack.getProperty('acceleration_enabled', 'value')
if accel_enabled:
global_accel_setting = global_stack.getProperty('acceleration_print', 'value')
accel_overrides["rate_mm_per_s_sq"] = {
"x": global_accel_setting,
"y": global_accel_setting
}
if global_stack.getProperty('acceleration_travel_enabled', 'value'):
travel_accel_setting = global_stack.getProperty('acceleration_travel', 'value')
bead_mode_overrides['Travel Move'] = {
"rate_mm_per_s_sq": {
"x": travel_accel_setting,
"y": travel_accel_setting
}
}
jerk_enabled = global_stack.getProperty('jerk_enabled', 'value')
if jerk_enabled:
global_jerk_setting = global_stack.getProperty('jerk_print', 'value')
accel_overrides["max_speed_change_mm_per_s"] = {
"x": global_jerk_setting,
"y": global_jerk_setting
}
if global_stack.getProperty('jerk_travel_enabled', 'value'):
travel_jerk_setting = global_stack.getProperty('jerk_travel', 'value')
if 'Travel Move' not in bead_mode_overrides:
bead_mode_overrides['Travel Move' ] = {}
bead_mode_overrides['Travel Move'].update({
"max_speed_change_mm_per_s": {
"x": travel_jerk_setting,
"y": travel_jerk_setting
}
})
# Get bead mode settings per extruder
available_bead_modes = {
"infill": "FILL",
"prime_tower": "PRIME_TOWER",
"roofing": "TOP_SURFACE",
"support_infill": "SUPPORT",
"support_interface": "SUPPORT_INTERFACE",
"wall_0": "WALL_OUTER",
"wall_x": "WALL_INNER",
"skirt_brim": "SKIRT"
}
for idx, extruder in enumerate(extruders):
for bead_mode_setting, bead_mode_tag in available_bead_modes.items():
ext_specific_tag = "%s_%s" % (bead_mode_tag, idx)
if accel_enabled or jerk_enabled:
bead_mode_overrides[ext_specific_tag] = {}
if accel_enabled:
accel_val = extruder.getProperty('acceleration_%s' % bead_mode_setting, 'value')
bead_mode_overrides[ext_specific_tag]["rate_mm_per_s_sq"] = {
"x": accel_val,
"y": accel_val
}
if jerk_enabled:
jerk_val = extruder.getProperty('jerk_%s' % bead_mode_setting, 'value')
bead_mode_overrides[ext_specific_tag][ "max_speed_change_mm_per_s"] = {
"x": jerk_val,
"y": jerk_val
}
meta["miracle_config"] = {"gaggles": {"instance0": {}}}
version_info = dict()

View file

@ -1,16 +1,21 @@
# Designed in January 2023 by GregValiant (Greg Foresi)
## My design intent was to make this as full featured and "industrial strength" as I could. People printing exotic materials on large custom printers may want to turn the fans off for certain layers, and then back on again later in the print. This script allows that.
# Functions:
## Remove all fan speed lines from the file (optional). This should be enabled for the first instance of the script. It is disabled by default in any following instances.
## "By Layer" allows the user to adjust the fan speed up, or down, or off, within the print. "By Feature" allows different fan speeds for different features (;TYPE:WALL-OUTER, etc.).
## If 'By Feature' then a Start Layer and/or an End Layer can be defined.
## Fan speeds are scaled PWM (0 - 255) or RepRap (0.0 - 1.0) depending on {machine_scale_fan_speed_zero_to_one}.
## A minimum fan speed of 12% is enforced. It is the slowest speed that my cooling fan will turn on so that's what I used. 'M106 S14' (as Cura might insert) was pretty useless.
## If multiple extruders have separate fan circuits the speeds are set at tool changes and conform to the layer or feature setting. There is support for up to 4 layer cooling fan circuits.
## My thanks to @5axes(@CUQ), @fieldOfView(@AHoeben), @Ghostkeeper, and @Torgeir. A special thanks to @RBurema for his patience in reviewing my 'non-pythonic' script.
## 9/14/23 (Greg Foresi) Added support for One-at-a-Time print sequence.
## 12/15/23 (Greg Foresi) Split off 'Single Fan By Layer', 'Multi-fan By Layer', 'Single Fan By Feature', and 'Multi-fan By Feature' from the main 'execute' script.
## 1/5/24 (Greg Foresi) Revised the regex replacements.
"""
Designed in January 2023 by GregValiant (Greg Foresi)
My design intent was to make this as full featured and "industrial strength" as I could. People printing exotic materials on large custom printers may want to turn the fans off for certain layers, and then back on again later in the print. This script allows that.
Functions:
Remove all fan speed lines from the file (optional). This should be enabled for the first instance of the script. It is disabled by default in any following instances.
"By Layer" allows the user to adjust the fan speed up, or down, or off, within the print. "By Feature" allows different fan speeds for different features (;TYPE:WALL-OUTER, etc.).
If 'By Feature' then a Start Layer and/or an End Layer can be defined.
Fan speeds are scaled PWM (0 - 255) or RepRap (0.0 - 1.0) depending on {machine_scale_fan_speed_zero_to_one}.
A minimum fan speed of 12% is enforced. It is the slowest speed that my cooling fan will turn on so that's what I used. 'M106 S14' (as Cura might insert) was pretty useless.
If multiple extruders have separate fan circuits the speeds are set at tool changes and conform to the layer or feature setting. There is support for up to 4 layer cooling fan circuits.
My thanks to @5axes(@CUQ), @fieldOfView(@AHoeben), @Ghostkeeper, and @Torgeir. A special thanks to @RBurema for his patience in reviewing my 'non-pythonic' script.
Changes:
09/14/23 (GV) Added support for One-at-a-Time print sequence.
12/15/23 (GV) Split off 'Single Fan By Layer', 'Multi-fan By Layer', 'Single Fan By Feature', and 'Multi-fan By Feature' from the main 'execute' script.
01/05/24 (GV) Revised the regex replacements.
12/11/24 (GV) Added 'off_fan_speed' for the idle nozzle layer cooling fan. It does not have to go to 0%.
03/22/25 (GV) Added 'Chamber Cooling Fan / Auxiliary Fan' control.
"""
from ..Script import Script
from UM.Application import Application
@ -43,7 +48,8 @@ class AddCoolingProfile(Script):
"type": "bool",
"enabled": true,
"value": true,
"default_value": true
"default_value": true,
"read_only": true
},
"feature_fan_start_layer":
{
@ -273,67 +279,180 @@ class AddCoolingProfile(Script):
"maximum_value": 100,
"unit": "% ",
"enabled": "fan_enable_raft"
},
"enable_off_fan_speed":
{
"label": "Enable 'Off speed' of the idle fan",
"description": "For machines with independent layer cooling fans. Leaving a fan running while the other nozzle is printing can help with oozing. You can pick the speed % for the idle nozzle layer cooling fan to hold at.",
"type": "bool",
"default_value": false,
"enabled": "enable_off_fan_speed_enable and self.extruder_count > 1"
},
"off_fan_speed":
{
"label": " 'Off' speed of idle nozzle fan",
"description": "This is the speed that the 'idle nozzle' layer cooling fan will maintain rather than being turned off completely.",
"type": "int",
"default_value": 35,
"minimum_value": 0,
"maximum_value": 100,
"unit": "% ",
"enabled": "enable_off_fan_speed_enable and enable_off_fan_speed and self.extruder_count > 1"
},
"enable_off_fan_speed_enable":
{
"label": "Hidden setting",
"description": "For dual extruder printers, this enables 'enable_off_fan_speed'.",
"type": "bool",
"default_value": false,
"enabled": false
},
"bv_fan_speed_control_enable":
{
"label": "Enable 'Chamber/Aux Fan' control",
"description": "Controls the 'Build Volume Fan' or an 'Auxiliary Fan' on printers with that hardware. Provides: 'On' layer, 'Off' layer, and PWM speed control of a secondary fan.",
"type": "bool",
"default_value": false,
"enabled": "enable_bv_fan"
},
"bv_fan_nr":
{
"label": " Chamber/Aux Fan Number",
"description": "The mainboard circuit number of the Chamber or Auxiliary Fan.",
"type": "int",
"unit": "# ",
"default_value": 0,
"minimum_value": 0,
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
},
"bv_fan_speed":
{
"label": " Chamber/Aux Fan Speed %",
"description": "The speed of the Chamber or Auxiliary Fan. This will be converted to PWM Duty Cycle (0-255) or (RepRap 0-1 if that is enabled in Cura). If your specified fan does not operate on variable speeds then set this to '100'.",
"type": "int",
"unit": "% ",
"default_value": 50,
"maximum_value": 100,
"minimum_value": 0,
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
},
"bv_fan_start_layer":
{
"label": " Chamber/Aux Fan Start Layer",
"description": "The layer to start the Chamber or Auxiliary Fan. Use the Cura preview layer number and the fan will start at the beginning of the layer.",
"type": "int",
"unit": "Layer# ",
"default_value": 1,
"minimum_value": 1,
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
},
"bv_fan_end_layer":
{
"label": " Chamber/Aux Fan End Layer",
"description": "The layer number for Chamber or Auxiliary Fan to turn off. Use the Cura preview layer number or '-1' to indicate the end of the print. The fan will run until the end of the layer",
"type": "int",
"unit": "Layer# ",
"default_value": -1,
"minimum_value": -1,
"enabled": "enable_bv_fan and bv_fan_speed_control_enable"
},
"enable_bv_fan":
{
"label": "Hidden setting",
"description": "This is enabled when machine_heated_bed is true, and in turn this enables 'bv_fan_speed_control_enable'.",
"type": "bool",
"default_value": false,
"enabled": false
}
}
}"""
def initialize(self) -> None:
super().initialize()
scripts = Application.getInstance().getGlobalContainerStack().getMetaDataEntry("post_processing_scripts")
self.global_stack = Application.getInstance().getGlobalContainerStack()
self.extruder_list = self.global_stack.extruderList
self.extruder_count = self.global_stack.getProperty("machine_extruder_count", "value")
scripts = self.global_stack.getMetaDataEntry("post_processing_scripts")
if scripts != None:
script_count = scripts.count("AddCoolingProfile")
if script_count > 0:
## Set 'Remove M106 lines' to "false" if there is already an instance of this script running.
# Set 'Remove M106 lines' to "false" if there is already an instance of this script running.
self._instance.setProperty("delete_existing_m106", "value", False)
self._instance.setProperty("enable_off_fan_speed_enable", "value", False)
if self.extruder_count > 1:
if self.extruder_list[0].getProperty("machine_extruder_cooling_fan_number", "value") != self.extruder_list[1].getProperty("machine_extruder_cooling_fan_number", "value"):
self._instance.setProperty("enable_off_fan_speed_enable", "value", True)
if bool(self.global_stack.getProperty("machine_heated_bed", "value")):
self._instance.setProperty("enable_bv_fan", "value", True)
def execute(self, data):
#Initialize variables that are buried in if statements.
mycura = Application.getInstance().getGlobalContainerStack()
"""
Collect the settings from Cura and from this script
params:
t0_fan thru t3_fan: The fan numbers for up to 4 layer cooling circuits
fan_mode: Whether the fan scale will be 0-255 PWM (when true) or 0-1 RepRap (when false)
bed_adhesion: Is only important if a raft is enabled
print_seuence: Options are slightly different if in One-at-a-Time mode
is_multi-fan: Used to distinguish between a multi-extruder with a single fan for each nozzle, or one fan for both nozzles.
is_multi_extr_print: For the slight difference in handling a multi-extruder printer and a print that only uses one of the extruders.
fan_list: A list of fan speeds (even numbered items) and layer numbers (odd numbered items)
feature_speed_list: A list of the speeds for each ';TYPE:' in the gcode
feature_name_list: The list of each 'TYPE' in the gcode
off_fan_speed: The speed that will be maintained by the fan for the inactive extruder (for an anti-oozing effect)
init_fan: The fan number of the first extruder used in a print
delete_existing_m106: The first instance of the script in the post processing list should remove the CUra M106 lines. Following instances should not delete the changes made by the first instance.
feature_fan_combing: Whether or not to shut the cooling fan off during travel moves.
the_start_layer: When in By Feature this is the user selected start of the fan changes.
the_end_layer: When in By Feature this is the user selected end of the fan changes
the_end_is_enabled: When in By Feature, if the fan control ends before the print ends, then this will enable the Final Fan Speed to carry through to the print end.
"""
# Exit if the gcode has been previously post-processed.
if ";POSTPROCESSED" in data[0]:
return data
# Initialize variables that are buried in if statements.
t0_fan = " P0"; t1_fan = " P0"; t2_fan = " P0"; t3_fan = " P0"; is_multi_extr_print = True
#Get some information from Cura-----------------------------------
extruder = mycura.extruderList
#This will be true when fan scale is 0-255pwm and false when it's RepRap 0-1 (Cura 5.x)
# This will be true when fan scale is 0-255pwm and false when it's RepRap 0-1 (Cura 5.x)
fan_mode = True
##For 4.x versions that don't have the 0-1 option
# For 4.x versions that don't have the 0-1 option
try:
fan_mode = not bool(extruder[0].getProperty("machine_scale_fan_speed_zero_to_one", "value"))
except:
fan_mode = not bool(self.extruder_list[0].getProperty("machine_scale_fan_speed_zero_to_one", "value"))
except AttributeError:
pass
bed_adhesion = (extruder[0].getProperty("adhesion_type", "value"))
extruder_count = mycura.getProperty("machine_extruder_count", "value")
print_sequence = str(mycura.getProperty("print_sequence", "value"))
#Assign the fan numbers to the tools------------------------------
if extruder_count == 1:
bed_adhesion = (self.extruder_list[0].getProperty("adhesion_type", "value"))
print_sequence = str(self.global_stack.getProperty("print_sequence", "value"))
# Assign the fan numbers to the tools
if self.extruder_count == 1:
is_multi_fan = False
is_multi_extr_print = False
if int((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value"))) > 0:
t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value")))
if int((self.extruder_list[0].getProperty("machine_extruder_cooling_fan_number", "value"))) > 0:
t0_fan = " P" + str((self.extruder_list[0].getProperty("machine_extruder_cooling_fan_number", "value")))
else:
#No P parameter if there is a single fan circuit------------------
# No P parameter if there is a single fan circuit
t0_fan = ""
#Get the cooling fan numbers for each extruder if the printer has multiple extruders
elif extruder_count > 1:
# Get the cooling fan numbers for each extruder if the printer has multiple extruders
elif self.extruder_count > 1:
is_multi_fan = True
t0_fan = " P" + str((extruder[0].getProperty("machine_extruder_cooling_fan_number", "value")))
t0_fan = " P" + str((self.extruder_list[0].getProperty("machine_extruder_cooling_fan_number", "value")))
if is_multi_fan:
if extruder_count > 1: t1_fan = " P" + str((extruder[1].getProperty("machine_extruder_cooling_fan_number", "value")))
if extruder_count > 2: t2_fan = " P" + str((extruder[2].getProperty("machine_extruder_cooling_fan_number", "value")))
if extruder_count > 3: t3_fan = " P" + str((extruder[3].getProperty("machine_extruder_cooling_fan_number", "value")))
if self.extruder_count > 1: t1_fan = " P" + str((self.extruder_list[1].getProperty("machine_extruder_cooling_fan_number", "value")))
if self.extruder_count > 2: t2_fan = " P" + str((self.extruder_list[2].getProperty("machine_extruder_cooling_fan_number", "value")))
if self.extruder_count > 3: t3_fan = " P" + str((self.extruder_list[3].getProperty("machine_extruder_cooling_fan_number", "value")))
#Initialize the fan_list with defaults----------------------------
# Initialize the fan_list with defaults
fan_list = ["z"] * 16
for num in range(0,15,2):
fan_list[num] = len(data)
fan_list[num + 1] = "M106 S0"
#Assign the variable values if "By Layer"-------------------------
# Assign the variable values if "By Layer"
by_layer_or_feature = self.getSettingValueByKey("fan_layer_or_feature")
if by_layer_or_feature == "by_layer":
## By layer doesn't do any feature search so there is no need to look for combing moves
# By layer doesn't do any feature search so there is no need to look for combing moves
feature_fan_combing = False
fan_list[0] = self.getSettingValueByKey("layer_fan_1")
fan_list[2] = self.getSettingValueByKey("layer_fan_2")
@ -343,25 +462,25 @@ class AddCoolingProfile(Script):
fan_list[10] = self.getSettingValueByKey("layer_fan_6")
fan_list[12] = self.getSettingValueByKey("layer_fan_7")
fan_list[14] = self.getSettingValueByKey("layer_fan_8")
## If there is no '/' delimiter then ignore the line else put the settings in a list
# If there is no '/' delimiter then ignore the line else put the settings in a list
for num in range(0,15,2):
if "/" in fan_list[num]:
fan_list[num + 1] = self._layer_checker(fan_list[num], "p", fan_mode)
fan_list[num] = self._layer_checker(fan_list[num], "l", fan_mode)
## Assign the variable values if "By Feature"
# Assign the variable values if "By Feature"
elif by_layer_or_feature == "by_feature":
the_start_layer = self.getSettingValueByKey("feature_fan_start_layer") - 1
the_end_layer = self.getSettingValueByKey("feature_fan_end_layer")
try:
if int(the_end_layer) != -1:
## Catch a possible input error.
# Catch a possible input error.
if the_end_layer < the_start_layer:
the_end_layer = the_start_layer
except:
the_end_layer = -1 ## If there is an input error default to the entire gcode file.
except ValueError:
the_end_layer = -1 # If there is an input error then default to the entire gcode file.
## Get the speed for each feature
# Get the speed for each feature
feature_name_list = []
feature_speed_list = []
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_skirt"), fan_mode)); feature_name_list.append(";TYPE:SKIRT")
@ -376,20 +495,29 @@ class AddCoolingProfile(Script):
feature_speed_list.append(self._feature_checker(self.getSettingValueByKey("feature_fan_feature_final"), fan_mode)); feature_name_list.append("FINAL_FAN")
feature_fan_combing = self.getSettingValueByKey("feature_fan_combing")
if the_end_layer > -1 and by_layer_or_feature == "by_feature":
## Required so the final speed input can be determined
# Required so the final speed input can be determined
the_end_is_enabled = True
else:
## There is no ending layer so do the whole file
# There is no ending layer so do the whole file
the_end_is_enabled = False
if the_end_layer == -1 or the_end_is_enabled == False:
the_end_layer = len(data) + 2
## Find the Layer0Index and the RaftIndex
# For multi-extruder printers with separate cooling fans the 'idle' nozzle fan can be left on for ooze control
off_fan_speed = 0
if self.extruder_count > 1:
if self.getSettingValueByKey("enable_off_fan_speed"):
if fan_mode:
off_fan_speed = round(int(self.getSettingValueByKey("off_fan_speed")) * 2.55)
else:
off_fan_speed = round(int(self.getSettingValueByKey("off_fan_speed")) * .01, 2)
# Find the Layer0Index and the RaftIndex
raft_start_index = 0
number_of_raft_layers = 0
layer_0_index = 0
## Catch the number of raft layers.
for l_num in range(1,10,1):
# Catch the number of raft layers.
for l_num in range(1,len(data) - 1):
layer = data[l_num]
if ";LAYER:-" in layer:
number_of_raft_layers += 1
@ -399,14 +527,14 @@ class AddCoolingProfile(Script):
layer_0_index = l_num
break
## Is this a single extruder print on a multi-extruder printer? - get the correct fan number for the extruder being used.
# Is this a single extruder print on a multi-extruder printer? - get the correct fan number for the extruder being used.
if is_multi_fan:
T0_used = False
T1_used = False
T2_used = False
T3_used = False
## Bypass the file header and ending gcode.
for num in range(1,len(data)-1,1):
# Bypass the file header and ending gcode.
for num in range(1,len(data)-1):
lines = data[num]
if "T0" in lines:
T0_used = True
@ -418,7 +546,7 @@ class AddCoolingProfile(Script):
T3_used = True
is_multi_extr_print = True if sum([T0_used, T1_used, T2_used, T3_used]) > 1 else False
## On a multi-extruder printer and single extruder print find out which extruder starts the file.
# On a multi-extruder printer and single extruder print find out which extruder starts the file.
init_fan = t0_fan
if not is_multi_extr_print:
startup = data[1]
@ -431,7 +559,7 @@ class AddCoolingProfile(Script):
elif line == "T3":
t0_fan = t3_fan
elif is_multi_extr_print:
## On a multi-extruder printer and multi extruder print find out which extruder starts the file.
# On a multi-extruder printer and multi extruder print find out which extruder starts the file.
startup = data[1]
lines = startup.split("\n")
for line in lines:
@ -445,23 +573,23 @@ class AddCoolingProfile(Script):
init_fan = t3_fan
else:
init_fan = ""
## Assign the variable values if "Raft Enabled"
# Assign the variable values if "Raft Enabled"
raft_enabled = self.getSettingValueByKey("fan_enable_raft")
if raft_enabled and bed_adhesion == "raft":
fan_sp_raft = self._feature_checker(self.getSettingValueByKey("fan_raft_percent"), fan_mode)
else:
fan_sp_raft = "M106 S0"
# Start to alter the data-----------------------------------------
## Strip the existing M106 lines from the file up to the end of the last layer. If a user wants to use more than one instance of this plugin then they won't want to erase the M106 lines that the preceding plugins inserted so 'delete_existing_m106' is an option.
# Start to alter the data
# Strip the existing M106 lines from the file up to the end of the last layer. If a user wants to use more than one instance of this plugin then they won't want to erase the M106 lines that the preceding plugins inserted so 'delete_existing_m106' is an option.
delete_existing_m106 = self.getSettingValueByKey("delete_existing_m106")
if delete_existing_m106:
## Start deleting from the beginning
# Start deleting from the beginning
start_from = int(raft_start_index)
else:
if by_layer_or_feature == "by_layer":
altered_start_layer = str(len(data))
## The fan list layers don't need to be in ascending order. Get the lowest.
# The fan list layers don't need to be in ascending order. Get the lowest.
for num in range(0,15,2):
try:
if int(fan_list[num]) < int(altered_start_layer):
@ -471,12 +599,12 @@ class AddCoolingProfile(Script):
elif by_layer_or_feature == "by_feature":
altered_start_layer = int(the_start_layer) - 1
start_from = int(layer_0_index) + int(altered_start_layer)
## Strip the M106 and M107 lines from the file
# Strip the M106 and M107 lines from the file
for l_index in range(int(start_from), len(data) - 1, 1):
data[l_index] = re.sub(re.compile("M106(.*)\n"), "", data[l_index])
data[l_index] = re.sub(re.compile("M107(.*)\n"), "", data[l_index])
## Deal with a raft and with One-At-A-Time print sequence
# Deal with a raft and with One-At-A-Time print sequence
if raft_enabled and bed_adhesion == "raft":
if print_sequence == "one_at_a_time":
for r_index in range(2,len(data)-2,1):
@ -486,9 +614,9 @@ class AddCoolingProfile(Script):
lines.insert(1, "M106 S0" + str(t0_fan))
if raft_enabled and bed_adhesion == "raft":
if ";LAYER:-" in data[r_index]:
## Turn the raft fan on
# Turn the raft fan on
lines.insert(1, fan_sp_raft + str(t0_fan))
## Shut the raft fan off at layer 0
# Shut the raft fan off at layer 0
if ";LAYER:0" in data[r_index]:
lines.insert(1,"M106 S0" + str(t0_fan))
data[r_index] = "\n".join(lines)
@ -496,13 +624,13 @@ class AddCoolingProfile(Script):
layer = data[raft_start_index]
lines = layer.split("\n")
if ";LAYER:-" in layer:
## Turn the raft fan on
# Turn the raft fan on
lines.insert(1, fan_sp_raft + str(init_fan))
layer = "\n".join(lines)
data[raft_start_index] = layer
layer = data[layer_0_index]
lines = layer.split("\n")
## Shut the raft fan off
# Shut the raft fan off
lines.insert(1, "M106 S0" + str(init_fan))
data[layer_0_index] = "\n".join(lines)
else:
@ -513,41 +641,44 @@ class AddCoolingProfile(Script):
lines.insert(1, "M106 S0" + str(t0_fan))
data[r_index] = "\n".join(lines)
## Turn off all fans at the end of data[1]. If more than one instance of this script is running then this will result in multiple M106 lines.
# Turn off all fans at the end of data[1]. If more than one instance of this script is running then this will result in multiple M106 lines.
temp_startup = data[1].split("\n")
temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t0_fan))
## If there are multiple cooling fans shut them all off
# If there are multiple cooling fans shut them all off
if is_multi_fan:
if extruder_count > 1 and t1_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t1_fan))
if extruder_count > 2 and t2_fan != t1_fan and t2_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t2_fan))
if extruder_count > 3 and t3_fan != t2_fan and t3_fan != t1_fan and t3_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t3_fan))
if self.extruder_count > 1 and t1_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t1_fan))
if self.extruder_count > 2 and t2_fan != t1_fan and t2_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t2_fan))
if self.extruder_count > 3 and t3_fan != t2_fan and t3_fan != t1_fan and t3_fan != t0_fan: temp_startup.insert(len(temp_startup)-2,"M106 S0" + str(t3_fan))
data[1] = "\n".join(temp_startup)
## If 'feature_fan_combing' is True then add additional 'MESH:NONMESH' lines for travel moves over 5 lines long
## For compatibility with 5.3.0 change any MESH:NOMESH to MESH:NONMESH.
# If 'feature_fan_combing' is True then add additional 'MESH:NONMESH' lines for travel moves over 5 lines long
# For compatibility with 5.3.0 change any MESH:NOMESH to MESH:NONMESH.
if feature_fan_combing:
for layer_num in range(2,len(data)):
layer = data[layer_num]
data[layer_num] = re.sub(";MESH:NOMESH", ";MESH:NONMESH", layer)
data = self._add_travel_comment(data, layer_0_index)
# Single Fan "By Layer"--------------------------------------------
if bool(self.getSettingValueByKey("bv_fan_speed_control_enable")):
data = self._control_bv_fan(data)
# Single Fan "By Layer"
if by_layer_or_feature == "by_layer" and not is_multi_fan:
return self._single_fan_by_layer(data, layer_0_index, fan_list, t0_fan)
# Multi-Fan "By Layer"---------------------------------------------
# Multi-Fan "By Layer"
if by_layer_or_feature == "by_layer" and is_multi_fan:
return self._multi_fan_by_layer(data, layer_0_index, fan_list, t0_fan, t1_fan, t2_fan, t3_fan)
return self._multi_fan_by_layer(data, layer_0_index, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, fan_mode, off_fan_speed)
#Single Fan "By Feature"------------------------------------------
# Single Fan "By Feature"
if by_layer_or_feature == "by_feature" and (not is_multi_fan or not is_multi_extr_print):
return self._single_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, feature_speed_list, feature_name_list, feature_fan_combing)
#Multi Fan "By Feature"-------------------------------------------
# Multi Fan "By Feature"
if by_layer_or_feature == "by_feature" and is_multi_fan:
return self._multi_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, feature_speed_list, feature_name_list, feature_fan_combing)
return self._multi_fan_by_feature(data, layer_0_index, the_start_layer, the_end_layer, the_end_is_enabled, fan_list, t0_fan, t1_fan, t2_fan, t3_fan, feature_speed_list, feature_name_list, feature_fan_combing, fan_mode, off_fan_speed)
# The Single Fan "By Layer"----------------------------------------
# The Single Fan "By Layer"
def _single_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str)->str:
layer_number = "0"
single_fan_data = data
@ -557,15 +688,15 @@ class AddCoolingProfile(Script):
for fan_line in fan_lines:
if ";LAYER:" in fan_line:
layer_number = str(fan_line.split(":")[1])
## If there is a match for the current layer number make the insertion
# If there is a match for the current layer number make the insertion
for num in range(0,15,2):
if layer_number == str(fan_list[num]):
layer = layer.replace(fan_lines[0],fan_lines[0] + "\n" + fan_list[num + 1] + str(t0_fan))
single_fan_data[l_index] = layer
return single_fan_data
# Multi-Fan "By Layer"-----------------------------------------
def _multi_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str)->str:
# Multi-Fan "By Layer"
def _multi_fan_by_layer(self, data: str, layer_0_index: int, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, fan_mode: bool, off_fan_speed: str)->str:
multi_fan_data = data
layer_number = "0"
current_fan_speed = "0"
@ -573,15 +704,16 @@ class AddCoolingProfile(Script):
this_fan = str(t0_fan)
start_index = str(len(multi_fan_data))
for num in range(0,15,2):
## The fan_list may not be in ascending order. Get the lowest layer number
# The fan_list may not be in ascending order. Get the lowest layer number
try:
if int(fan_list[num]) < int(start_index):
start_index = str(fan_list[num])
except:
except ValueError:
pass
## Move the start point if delete_existing_m106 is false
# Move the start point if delete_existing_m106 is false
start_index = int(start_index) + int(layer_0_index)
## Track the tool number
# Track the tool number
for num in range(1,int(start_index),1):
layer = multi_fan_data[num]
lines = layer.split("\n")
@ -598,18 +730,19 @@ class AddCoolingProfile(Script):
elif line == "T3":
prev_fan = this_fan
this_fan = t3_fan
# With Active Tool tracked - now the body of changes can start
for l_index in range(int(start_index),len(multi_fan_data)-1,1):
modified_data = ""
layer = multi_fan_data[l_index]
fan_lines = layer.split("\n")
for fan_line in fan_lines:
## Prepare to shut down the previous fan and start the next one.
# Prepare to turn off the previous fan and start the next one.
if fan_line.startswith("T"):
if fan_line == "T0": this_fan = str(t0_fan)
if fan_line == "T1": this_fan = str(t1_fan)
if fan_line == "T2": this_fan = str(t2_fan)
if fan_line == "T3": this_fan = str(t3_fan)
modified_data += "M106 S0" + prev_fan + "\n"
modified_data += f"M106 S{off_fan_speed}" + prev_fan + "\n"
modified_data += fan_line + "\n"
modified_data += "M106 S" + str(current_fan_speed) + this_fan + "\n"
prev_fan = this_fan
@ -620,19 +753,22 @@ class AddCoolingProfile(Script):
if layer_number == str(fan_list[num]):
modified_data += fan_list[num + 1] + this_fan + "\n"
current_fan_speed = str(fan_list[num + 1].split("S")[1])
current_fan_speed = str(current_fan_speed.split(" ")[0]) ## Just in case
current_fan_speed = str(current_fan_speed.split(" ")[0]) # Just in case
else:
modified_data += fan_line + "\n"
if modified_data.endswith("\n"): modified_data = modified_data[0:-1]
multi_fan_data[l_index] = modified_data
# Insure the fans get shut off if 'off_fan_speed' was enabled
if self.extruder_count > 1 and self.getSettingValueByKey("enable_off_fan_speed"):
multi_fan_data[-1] += "M106 S0 P1\nM106 S0 P0\n"
return multi_fan_data
# Single fan by feature-----------------------------------------------
# Single fan by feature
def _single_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool)->str:
single_fan_data = data
layer_number = "0"
index = 1
## Start with layer:0
# Start with layer:0
for l_index in range(layer_0_index,len(single_fan_data)-1,1):
modified_data = ""
layer = single_fan_data[l_index]
@ -652,15 +788,16 @@ class AddCoolingProfile(Script):
if feature_fan_combing == True:
modified_data += "M106 S0" + t0_fan + "\n"
modified_data += line + "\n"
## If an End Layer is defined and is less than the last layer then insert the Final Speed
# If an End Layer is defined and is less than the last layer then insert the Final Speed
if line == ";LAYER:" + str(the_end_layer) and the_end_is_enabled == True:
modified_data += feature_speed_list[len(feature_speed_list) - 1] + t0_fan + "\n"
if modified_data.endswith("\n"): modified_data = modified_data[0: - 1]
single_fan_data[l_index] = modified_data
return single_fan_data
# Multi-fan by feature------------------------------------------------
def _multi_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool)->str:
# Multi-fan by feature
def _multi_fan_by_feature(self, data: str, layer_0_index: int, the_start_layer: str, the_end_layer: str, the_end_is_enabled: str, fan_list: str, t0_fan: str, t1_fan: str, t2_fan: str, t3_fan: str, feature_speed_list: str, feature_name_list: str, feature_fan_combing: bool, fan_mode: bool, off_fan_speed: str)->str:
multi_fan_data = data
layer_number = "0"
start_index = 1
@ -673,7 +810,7 @@ class AddCoolingProfile(Script):
if ";LAYER:" + str(the_start_layer) + "\n" in layer:
start_index = int(my_index) - 1
break
## Track the previous tool changes
# Track the previous tool changes
for num in range(1,start_index,1):
layer = multi_fan_data[num]
lines = layer.split("\n")
@ -690,7 +827,7 @@ class AddCoolingProfile(Script):
elif line == "T3":
prev_fan = this_fan
this_fan = t3_fan
## Get the current tool.
# Get the current tool.
for l_index in range(start_index,start_index + 1,1):
layer = multi_fan_data[l_index]
lines = layer.split("\n")
@ -702,7 +839,7 @@ class AddCoolingProfile(Script):
if line == "T3": this_fan = t3_fan
prev_fan = this_fan
## Start to make insertions-------------------------------------
# Start to make insertions
for l_index in range(start_index+1,len(multi_fan_data)-1,1):
layer = multi_fan_data[l_index]
lines = layer.split("\n")
@ -712,10 +849,10 @@ class AddCoolingProfile(Script):
if line == "T1": this_fan = t1_fan
if line == "T2": this_fan = t2_fan
if line == "T3": this_fan = t3_fan
## Turn off the prev fan
modified_data += "M106 S0" + prev_fan + "\n"
# Turn off the prev fan
modified_data += f"M106 S{off_fan_speed}" + prev_fan + "\n"
modified_data += line + "\n"
## Turn on the current fan
# Turn on the current fan
modified_data += "M106 S" + str(current_fan_speed) + this_fan + "\n"
prev_fan = this_fan
if ";LAYER:" in line:
@ -725,34 +862,39 @@ class AddCoolingProfile(Script):
temp = line.split(" ")[0]
try:
name_index = feature_name_list.index(temp)
except:
except IndexError:
name_index = -1
if name_index != -1:
modified_data += line + "\n" + feature_speed_list[name_index] + this_fan + "\n"
#modified_data += feature_speed_list[name_index] + this_fan + "\n"
current_fan_speed = str(feature_speed_list[name_index].split("S")[1])
elif ";MESH:NONMESH" in line:
if feature_fan_combing == True:
modified_data += line + "\n"
modified_data += "M106 S0" + this_fan + "\n"
modified_data += f"M106 S{off_fan_speed}" + this_fan + "\n"
current_fan_speed = "0"
else:
modified_data += line + "\n"
## If an end layer is defined - Insert the final speed and set the other variables to Final Speed to finish the file
## There cannot be a break here because if there are multiple fan numbers they still need to be shut off and turned on.
# If an end layer is defined - Insert the final speed and set the other variables to Final Speed to finish the file
# There cannot be a 'break' here because if there are multiple fan numbers they still need to be shut off and turned on.
elif line == ";LAYER:" + str(the_end_layer):
modified_data += feature_speed_list[len(feature_speed_list) - 1] + this_fan + "\n"
for set_speed in range(0, len(feature_speed_list) - 2):
feature_speed_list[set_speed] = feature_speed_list[len(feature_speed_list) - 1]
else:
## Layer and Tool get inserted into modified_data above. All other lines go into modified_data here
# Layer and Tool get inserted into modified_data above. All other lines go into modified_data here
if not line.startswith("T") and not line.startswith(";LAYER:"): modified_data += line + "\n"
if modified_data.endswith("\n"): modified_data = modified_data[0: - 1]
multi_fan_data[l_index] = modified_data
modified_data = ""
# Insure the fans get shut off if 'off_fan_speed' was enabled
if self.extruder_count > 1 and self.getSettingValueByKey("enable_off_fan_speed"):
multi_fan_data[-1] += "M106 S0 P1\nM106 S0 P0\n"
return multi_fan_data
#Try to catch layer input errors, set the minimum speed to 12%, and put the strings together
# Try to catch layer input errors, set the minimum speed to 12%, and put the strings together
def _layer_checker(self, fan_string: str, ty_pe: str, fan_mode: bool) -> str:
fan_string_l = str(fan_string.split("/")[0])
try:
@ -768,7 +910,7 @@ class AddCoolingProfile(Script):
if int(fan_string_p) > 100: fan_string_p = "100"
except ValueError:
fan_string_p = "0"
## Set the minimum fan speed to 12%
# Set the minimum fan speed to 12%
if int(fan_string_p) < 12 and int(fan_string_p) != 0:
fan_string_p = "12"
fan_layer_line = str(fan_string_l)
@ -784,7 +926,7 @@ class AddCoolingProfile(Script):
#Try to catch feature input errors, set the minimum speed to 12%, and put the strings together when 'By Feature'
def _feature_checker(self, fan_feat_string: int, fan_mode: bool) -> str:
if fan_feat_string < 0: fan_feat_string = 0
## Set the minimum fan speed to 12%
# Set the minimum fan speed to 12%
if fan_feat_string > 0 and fan_feat_string < 12: fan_feat_string = 12
if fan_feat_string > 100: fan_feat_string = 100
if fan_mode:
@ -798,7 +940,7 @@ class AddCoolingProfile(Script):
for lay_num in range(int(lay_0_index), len(comment_data)-1,1):
layer = comment_data[lay_num]
lines = layer.split("\n")
## Copy the data to new_data and make the insertions there
# Copy the data to new_data and make the insertions there
new_data = lines
g0_count = 0
g0_index = -1
@ -818,12 +960,12 @@ class AddCoolingProfile(Script):
if g0_index == -1:
g0_index = lines.index(line)
elif not line.startswith("G0 ") and not is_travel:
## Add additional 'NONMESH' lines to shut the fan off during long combing moves--------
# Add additional 'NONMESH' lines to shut the fan off during long combing moves
if g0_count > 5:
if not is_travel:
new_data.insert(g0_index + insert_index, ";MESH:NONMESH")
insert_index += 1
## Add the feature_type at the end of the combing move to turn the fan back on
# Add the feature_type at the end of the combing move to turn the fan back on
new_data.insert(g0_index + g0_count + 1, feature_type)
insert_index += 1
g0_count = 0
@ -834,4 +976,35 @@ class AddCoolingProfile(Script):
g0_index = -1
is_travel = False
comment_data[lay_num] = "\n".join(new_data)
return comment_data
return comment_data
def _control_bv_fan(self, bv_data: str) -> str:
# Control any secondary fan. Can be used for an Auxilliary/Chamber fan
bv_start_layer = self.getSettingValueByKey("bv_fan_start_layer") - 1
bv_end_layer = self.getSettingValueByKey("bv_fan_end_layer")
bv_fan_nr = self.getSettingValueByKey("bv_fan_nr")
if bv_end_layer != -1:
bv_end_layer -= 1
# Get the PWM speed or if RepRap then the 0-1 speed
if self.extruder_list[0].getProperty("machine_scale_fan_speed_zero_to_one", "value"):
bv_fan_speed = round(self.getSettingValueByKey("bv_fan_speed") * .01, 1)
else:
bv_fan_speed = int(self.getSettingValueByKey("bv_fan_speed") * 2.55)
# Turn the chamber fan on
for index, layer in enumerate(bv_data):
if f";LAYER:{bv_start_layer}\n" in layer:
bv_data[index] = re.sub(f";LAYER:{bv_start_layer}", f";LAYER:{bv_start_layer}\nM106 S{bv_fan_speed} P{bv_fan_nr}",layer)
break
# Turn the chamber fan off
if bv_end_layer == -1:
bv_data[len(bv_data)-2] += f"M106 S0 P{bv_fan_nr}\n"
else:
for index, layer in enumerate(bv_data):
if f";LAYER:{bv_end_layer}\n" in layer:
lines = layer.split("\n")
for fdex, line in enumerate(lines):
if ";TIME_ELAPSED:" in line:
lines[fdex] = f"M106 S0 P{bv_fan_nr}\n" + line
bv_data[index] = "\n".join(lines)
break
return bv_data

View file

@ -92,7 +92,7 @@ class FilamentChange(Script):
"type": "float",
"default_value": 0,
"minimum_value": 0,
"enabled": "enabled"
"enabled": "enabled and not firmware_config"
},
"retract_method":
{

View file

@ -496,7 +496,7 @@ class PurgeLinesAndUnload(Script):
"""Generates G-code lines for prime blob adjustment."""
gcode_lines = [
f"G1 F{retract_speed} E{retract_distance} ; Unretract",
"G92 E0 ; Reset extruder"
"G92 E0 ; Reset extruder\n"
]
return "\n".join(gcode_lines)

View file

@ -101,7 +101,8 @@ class RemovableDriveOutputDevice(OutputDevice):
self._stream = open(file_name, "wt", buffering = 1, encoding = "utf-8")
else: #Binary mode.
self._stream = open(file_name, "wb", buffering = 1)
job = WriteFileJob(writer, self._stream, nodes, preferred_format["mode"])
writer_args = {"mime_type": preferred_format["mime_type"]}
job = WriteFileJob(writer, self._stream, nodes, preferred_format["mode"], writer_args)
job.setFileName(file_name)
job.progress.connect(self._onProgress)
job.finished.connect(self._onFinished)

View file

@ -51,7 +51,7 @@ class UFPWriter(MeshWriter):
# Qt thread. The File read/write operations right now are executed on separated threads because they are scheduled
# by the Job class.
@call_on_qt_thread
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode):
def write(self, stream, nodes, mode = MeshWriter.OutputMode.BinaryMode, **kwargs):
archive = VirtualFile()
archive.openStream(stream, "application/x-ufp", OpenMode.WriteOnly)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 620 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 874 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 90 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 735 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,267 @@
{
"version": 2,
"name": "BambuLab base definition",
"inherits": "fdmprinter",
"metadata":
{
"visible": false,
"author": "UltiMaker",
"manufacturer": "BambuLab",
"file_formats": "application/vnd.bambulab-package.3dmanufacturing-3dmodel+xml"
},
"overrides":
{
"acceleration_infill": { "value": "acceleration_print" },
"acceleration_layer_0": { "value": 2000 },
"acceleration_prime_tower": { "value": "acceleration_print" },
"acceleration_print": { "value": 20000 },
"acceleration_print_layer_0": { "value": "acceleration_layer_0" },
"acceleration_roofing": { "value": "acceleration_wall_0" },
"acceleration_skirt_brim": { "value": "acceleration_layer_0" },
"acceleration_support": { "value": "acceleration_print" },
"acceleration_support_bottom": { "value": "acceleration_support_interface" },
"acceleration_support_infill": { "value": "acceleration_support" },
"acceleration_support_interface": { "value": "acceleration_support" },
"acceleration_support_roof": { "value": "acceleration_support_interface" },
"acceleration_topbottom": { "value": "acceleration_print" },
"acceleration_travel": { "value": 20000 },
"acceleration_travel_enabled": { "value": true },
"acceleration_travel_layer_0": { "value": "acceleration_layer_0" },
"acceleration_wall": { "value": "acceleration_print/8" },
"acceleration_wall_0": { "value": "acceleration_wall" },
"acceleration_wall_0_roofing": { "value": "acceleration_wall_0" },
"acceleration_wall_x": { "value": "acceleration_print" },
"acceleration_wall_x_roofing": { "value": "acceleration_wall" },
"adhesion_type": { "value": "'skirt'" },
"bottom_thickness": { "value": 0.6 },
"bridge_skin_speed":
{
"unit": "mm/s",
"value": "bridge_wall_speed"
},
"bridge_sparse_infill_max_density": { "value": 50 },
"bridge_wall_min_length": { "value": 10 },
"bridge_wall_speed":
{
"unit": "mm/s",
"value": 50
},
"cool_min_layer_time": { "value": 6 },
"cool_min_speed": { "value": 6 },
"cool_min_temperature": { "value": "material_print_temperature-15" },
"default_material_print_temperature": { "maximum_value_warning": 320 },
"extra_infill_lines_to_support_skins": { "value": "'walls_and_lines'" },
"gradual_flow_enabled": { "value": false },
"hole_xy_offset": { "value": 0.075 },
"infill_overlap": { "value": 10 },
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'gyroid'" },
"infill_sparse_density": { "value": 15 },
"infill_wall_line_count": { "value": "1 if infill_sparse_density > 80 else 0" },
"jerk_infill": { "value": "jerk_print" },
"jerk_layer_0": { "value": "jerk_print/2" },
"jerk_prime_tower": { "value": "jerk_print" },
"jerk_print": { "value": "50" },
"jerk_print_layer_0": { "value": "jerk_layer_0" },
"jerk_roofing": { "value": "jerk_wall_0" },
"jerk_skirt_brim": { "value": "jerk_layer_0" },
"jerk_support": { "value": "jerk_print" },
"jerk_support_bottom": { "value": "jerk_support_interface" },
"jerk_support_infill": { "value": "jerk_support" },
"jerk_support_interface": { "value": "jerk_support" },
"jerk_support_roof": { "value": "jerk_support_interface" },
"jerk_topbottom": { "value": "jerk_print" },
"jerk_travel": { "value": 50 },
"jerk_travel_enabled": { "value": true },
"jerk_travel_layer_0": { "value": "jerk_travel" },
"jerk_wall": { "value": "jerk_print/5" },
"jerk_wall_0": { "value": "jerk_wall" },
"jerk_wall_0_roofing": { "value": "jerk_wall_0" },
"jerk_wall_x": { "value": "jerk_print" },
"jerk_wall_x_roofing": { "value": "jerk_wall_0" },
"line_width": { "value": 0.42 },
"machine_acceleration": { "value": 10000 },
"machine_buildplate_type":
{
"default_value": "textured_pei_plate",
"options":
{
"cool_plate": "Cool Plate",
"engineering_plate": "Engineering Plate",
"high_temp_plate": "High Temp Plate",
"textured_pei_plate": "Textured PEI Plate"
}
},
"machine_center_is_zero": { "default_value": false },
"machine_gcode_flavor": { "default_value": "BambuLab" },
"machine_heated_bed": { "default_value": true },
"machine_max_feedrate_e": { "value": 150 },
"machine_max_feedrate_x": { "value": 500 },
"machine_max_feedrate_y": { "value": 500 },
"machine_max_feedrate_z": { "value": 15 },
"machine_max_jerk_e": { "default_value": 100 },
"machine_max_jerk_xy": { "default_value": 5000 },
"machine_max_jerk_z": { "default_value": 100 },
"machine_nozzle_cool_down_speed": { "default_value": 1.3 },
"machine_nozzle_heat_up_speed": { "default_value": 1.9 },
"machine_nozzle_size": { "default_value": 0.4 },
"machine_show_variants": { "value": true },
"machine_use_extruder_offset_to_offset_coords": { "value": false },
"material_diameter": { "default_value": 1.75 },
"material_flush_purge_length":
{
"default_value": 80,
"enabled": "not prime_tower_enable"
},
"material_flush_purge_speed":
{
"default_value": 500,
"enabled": "not prime_tower_enable"
},
"material_max_flowrate": { "enabled": true },
"max_skin_angle_for_expansion": { "value": 45 },
"meshfix_maximum_resolution": { "value": 0.4 },
"min_infill_area": { "default_value": 10 },
"optimize_wall_printing_order": { "value": false },
"prime_tower_enable": { "default_value": true },
"prime_tower_line_width": { "value": "1.5 * line_width" },
"prime_tower_min_volume": { "default_value": 250 },
"prime_tower_size": { "default_value": 40 },
"relative_extrusion": { "value": true },
"retraction_amount": { "value": 0.5 },
"retraction_combing_max_distance": { "value": 100 },
"retraction_extra_prime_amount": { "value": 0.12 },
"retraction_hop": { "value": 0.2 },
"retraction_hop_after_extruder_switch_height": { "value": 2 },
"retraction_hop_enabled": { "value": true },
"retraction_min_travel": { "value": "5 if support_enable and support_structure=='tree' else line_width * 2" },
"retraction_prime_speed": { "value": 15 },
"retraction_speed": { "value": 30 },
"skin_edge_support_thickness": { "value": 0 },
"skin_material_flow": { "value": 95 },
"skin_overlap": { "value": 0 },
"skin_preshrink": { "value": 0 },
"skirt_brim_speed": { "maximum_value_warning": 500 },
"skirt_line_count": { "value": 5 },
"small_skin_on_surface": { "value": false },
"small_skin_width": { "value": 4 },
"speed_infill":
{
"maximum_value_warning": 500,
"value": "speed_print"
},
"speed_ironing":
{
"maximum_value_warning": 500,
"value": 20
},
"speed_layer_0":
{
"maximum_value_warning": 500,
"value": "speed_print/6"
},
"speed_prime_tower":
{
"maximum_value_warning": 500,
"value": "speed_wall"
},
"speed_print":
{
"maximum_value_warning": 500,
"value": 300
},
"speed_print_layer_0":
{
"maximum_value_warning": 500,
"value": "speed_layer_0"
},
"speed_roofing":
{
"maximum_value_warning": 500,
"value": "speed_wall"
},
"speed_support":
{
"maximum_value_warning": 500,
"value": "speed_wall_0"
},
"speed_support_bottom":
{
"maximum_value_warning": 500,
"value": "speed_support_interface"
},
"speed_support_infill":
{
"maximum_value_warning": 500,
"value": "speed_support"
},
"speed_support_interface":
{
"maximum_value_warning": 500,
"value": 50
},
"speed_support_roof":
{
"maximum_value_warning": 500,
"value": "speed_support_interface"
},
"speed_topbottom":
{
"maximum_value_warning": 500,
"value": "speed_print"
},
"speed_travel":
{
"maximum_value": 500,
"value": 500
},
"speed_travel_layer_0":
{
"maximum_value": 500,
"value": 150
},
"speed_wall":
{
"maximum_value_warning": 500,
"value": "speed_print*2/3"
},
"speed_wall_0":
{
"maximum_value_warning": 500,
"value": "speed_wall"
},
"speed_wall_0_roofing":
{
"maximum_value_warning": 500,
"value": "speed_wall"
},
"speed_wall_x":
{
"maximum_value_warning": 500,
"value": "speed_print"
},
"speed_wall_x_roofing":
{
"maximum_value_warning": 500,
"value": "speed_wall"
},
"support_brim_line_count": { "value": 5 },
"support_infill_rate": { "value": "80 if gradual_support_infill_steps != 0 else 15" },
"support_pattern": { "value": "'gyroid'" },
"support_structure": { "value": "'tree'" },
"switch_extruder_retraction_amount": { "value": 5 },
"travel_avoid_other_parts": { "value": false },
"wall_0_acceleration": { "value": 1000 },
"wall_0_deceleration": { "value": 1000 },
"wall_0_end_speed_ratio": { "value": 100 },
"wall_0_speed_split_distance": { "value": 0.2 },
"wall_0_start_speed_ratio": { "value": 100 },
"wall_0_wipe_dist": { "value": 0 },
"wall_material_flow": { "value": 95 },
"wall_overhang_angle": { "value": 10 },
"wall_overhang_speed_factors": { "default_value": "[25,15,5,5]" },
"wall_x_material_flow": { "value": 100 },
"z_seam_corner": { "value": "'z_seam_corner_weighted'" },
"z_seam_position": { "value": "'backright'" },
"z_seam_type": { "value": "'sharpest_corner'" }
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,39 @@
{
"version": 2,
"name": "Biqu B2",
"inherits": "biqu_b1",
"metadata":
{
"visible": true,
"author": "Boris Juraga",
"has_textured_buildplate": true,
"machine_extruder_trains":
{
"0": "biqu_b2_extruder_0",
"1": "biqu_b2_extruder_1"
},
"quality_definition": "biqu_b2"
},
"overrides":
{
"gantry_height": { "value": 27.5 },
"machine_end_gcode": { "default_value": ";BEGIN OF CUSTOM END GCODE\nM104 S0\nM140 S0\n;Retract the filament\nG91\nG1 E-30 F300\nG1 Z5\nG90\nG28 X0 Y{machine_depth}\n;END OF CUSTOM END GCODE" },
"machine_extruder_count": { "default_value": 2 },
"machine_extruders_share_heater": { "default_value": true },
"machine_extruders_share_nozzle": { "default_value": true },
"machine_extruders_shared_nozzle_initial_retraction": { "default_value": 30 },
"machine_head_with_fans_polygon":
{
"default_value": [
[-33, 35],
[-33, -23],
[33, -23],
[33, 35]
]
},
"machine_name": { "default_value": "BIQU B2" },
"machine_start_gcode": { "default_value": ";BEGIN OF CUSTOM START GCODE\nG28 ;Home\nG1 Z15.0 F6000 ;Move the platform down 15mm\n;Prime the extruder\nM109 S{material_print_temperature_layer_0} ; Wait for Extruder temperature\nT0\nG92 E0\nG1 F1200 E-30\nG92 E0\nM109 S{material_print_temperature_layer_0} ; Wait for Extruder temperature\nT1\nG92 E0\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X6.1 Y20 Z0.3 F5000.0 ; Move to start position\nM117 Purging\nG1 X6.1 Y200.0 Z0.3 F1500.0 E10 ; Draw the first line\nG1 X6.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X6.4 Y20 Z0.3 F1500.0 E20 ; Draw the second line\nG1 X6.7 Y20 Z0.3 F5000.0 ; Move to side a little\nG1 X6.7 Y200.0 Z0.3 F1500.0 E30 ; Draw the three line\nG1 X7.0 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X7.0 Y20 Z0.3 F1500.0 E40 ; Draw the four line\nG1 X7.3 Y20 Z0.3 F5000.0 ; Move to side a little\nG1 X7.3 Y200.0 Z0.3 F1500.0 E50 ; Draw the four line\nG92 E0 \nT1\nG92 E0\nG1 F1200 E-30\nG92 E0\nT0\nG92 E0\nG1 F1200 E30\nG92 E0\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X9.1 Y20 Z0.3 F5000.0 ; Move to start position\nM117 Purging\nG1 X9.1 Y200.0 Z0.3 F1500.0 E10 ; Draw the first line\nG1 X9.4 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X9.4 Y20 Z0.3 F1500.0 E20 ; Draw the second line\nG1 X9.7 Y20 Z0.3 F5000.0 ; Move to side a little\nG1 X9.7 Y200.0 Z0.3 F1500.0 E30 ; Draw the three line\nG1 X10.0 Y200.0 Z0.3 F5000.0 ; Move to side a little\nG1 X10.0 Y20 Z0.3 F1500.0 E40 ; Draw the four line\nG1 X10.3 Y20 Z0.3 F5000.0 ; Move to side a little\nG1 X10.3 Y200.0 Z0.3 F1500.0 E50 ; Draw the four line\nT0\nG92 E0\nG1 F1200 E-30\nG92 E0\nG92 E0\nT{initial_extruder_nr} ; RESET EXTRUDER TO INITIAL\n; start print\n;END OF CUSTOM START GCODE" },
"prime_tower_enable": { "default_value": true },
"prime_tower_mode": { "default_value": "interleaved" }
}
}

View file

@ -48,7 +48,7 @@
"machine_width": { "default_value": 220 },
"material_print_temp_wait": { "default_value": false },
"retraction_amount": { "default_value": 0.8 },
"retraction_combing": { "value": "no_outer_surfaces" },
"retraction_combing": { "value": "'no_outer_surfaces'" },
"retraction_combing_max_distance": { "value": 5.0 },
"retraction_extrusion_window": { "value": "retraction_amount" },
"retraction_min_travel": { "value": 2.0 },

View file

@ -214,8 +214,8 @@
},
"machine_buildplate_type":
{
"label": "Build Plate Material",
"description": "The material of the build plate installed on the printer.",
"label": "Build Plate Type",
"description": "The type of build plate installed on the printer.",
"default_value": "glass",
"type": "enum",
"options":
@ -388,7 +388,8 @@
"Makerbot": "Makerbot",
"BFB": "Bits from Bytes",
"MACH3": "Mach3",
"Repetier": "Repetier"
"Repetier": "Repetier",
"BambuLab": "BambuLab"
},
"default_value": "RepRap (Marlin/Sprinter)",
"settable_per_mesh": false,
@ -3376,6 +3377,20 @@
"settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false
},
"material_max_flowrate":
{
"default_value": 16,
"description": "Maximum flow rate that the printer can extrude for the material",
"enabled": false,
"label": "Material Maximum Flow Rate",
"maximum_value": "machine_max_feedrate_e * (material_diameter/2)**2 * math.pi",
"minimum_value": "0",
"settable_per_extruder": true,
"settable_per_mesh": false,
"type": "float",
"unit": "mm\u00b3/s",
"value": "16"
}
}
},
@ -4855,7 +4870,7 @@
},
"build_fan_full_at_height":
{
"label": "Build Fan Speed at Height",
"label": "Build Volume Fan Speed at Height",
"description": "The height at which the fans spin on regular fan speed. At the layers below the fan speed gradually increases from Initial Fan Speed to Regular Fan Speed.",
"unit": "mm",
"type": "float",
@ -4870,8 +4885,8 @@
{
"build_fan_full_layer":
{
"label": "Build Fan Speed at Layer",
"description": "The layer at which the build fans spin on full fan speed. This value is calculated and rounded to a whole number.",
"label": "Build Volume Fan Speed at Layer",
"description": "The layer at which the build-volume fans spin on full fan speed. This value is calculated and rounded to a whole number.",
"type": "int",
"default_value": 0,
"minimum_value": "0",
@ -4884,6 +4899,34 @@
}
}
},
"build_volume_fan_speed_0":
{
"label": "Initial Layers Build Volume Fan Speed",
"description": "The fan speed (as a percentage) for the auxiliary or build-volume fan, that is set until the layer specified at 'Build Volume Fan Speed at Layer' is reached. After that, the speed is set by 'Build Volume Fan Speed' instead (so not this 'Initial Layers' one).",
"unit": "%",
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"default_value": 0,
"enabled": "build_volume_fan_nr != 0",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"build_volume_fan_speed":
{
"label": "Build Volume Fan Speed",
"description": "The fan speed (as a percentage) for the auxiliary or build-volume fan, that is set from the moment that the layer specified at 'Build Volume Fan Speed at Layer' is reached and onwards. Before that, the speed is set by 'Initial Layers Build Volume Fan Speed' instead.",
"unit": "%",
"type": "float",
"minimum_value": "0",
"maximum_value": "100",
"default_value": 100,
"enabled": "build_volume_fan_nr != 0",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
},
"cool_fan_speed":
{
"label": "Fan Speed",
@ -7465,6 +7508,17 @@
"limit_to_extruder": "raft_surface_extruder_nr"
}
}
},
"machine_scan_first_layer":
{
"default_value": false,
"description": "Whether to scan the first layer for layer adhesion problems.",
"enabled": false,
"label": "Scan the first layer",
"settable_per_extruder": false,
"settable_per_mesh": false,
"settable_per_meshgroup": false,
"type": "bool"
}
}
},

View file

@ -0,0 +1,59 @@
{
"version": 2,
"name": "Geeetech M1",
"inherits": "Geeetech_Base_Single_Extruder",
"metadata":
{
"visible": true,
"machine_extruder_trains": { "0": "Geeetech_Single_Extruder" }
},
"overrides":
{
"adhesion_type": { "value": "'brim'" },
"brim_width": { "value": 2 },
"gantry_height": { "value": 35 },
"machine_depth": { "default_value": 105 },
"machine_end_gcode": { "default_value": "G91 ;Switch to relative positioning\nG1 E-2.5 F2700 ;Retract filament\nG1 E-1.5 Z0.2 F2400 ;Retract and raise Z\nG1 X5 Y5 F3000 ;Move away\nG1 Z10 ;lift print head\nG90 ;Switch to absolute positioning\nG28 X Y ;homing XY\nM106 S0 ;off Fan\nM104 S0 ;Cooldown hotend\nM140 S0 ;Cooldown bed\nM84 X Y E ;Disable steppers" },
"machine_head_with_fans_polygon":
{
"default_value": [
[-31, 31],
[34, 31],
[34, -40],
[-31, -40]
]
},
"machine_height": { "default_value": 95 },
"machine_name": { "default_value": "Geeetech M1" },
"machine_start_gcode": { "default_value": ";Official wiki URL for Geeetech M1:https://www.geeetech.com/wiki/index.php/Geeetech_M1_3D_printer \nM104 S{material_print_temperature_layer_0} ; Set Hotend Temperature\nM140 S{material_bed_temperature_layer_0} ; Set Bed Temperature\n;M190 S{material_bed_temperature_layer_0} ; Wait for Bed Temperature\nM109 S{material_print_temperature_layer_0} ; Wait for Hotend Temperature\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nM107 ;Off Fan\nM300 S2500 P1000 ;Play a short tune\nG1 Z0.28 ;Move Z Axis up little to prevent scratching of Heat Bed\nG92 E0 ;Reset Extruder\nG1 Y3 F2400 ;Move to start position\nG1 X75 E40 F500 ;Draw a filament line\nG92 E0 ;Reset Extruder\n;G1 E-0.2 F3000 ;Retract a little\nG1 Z2.0 F3000 ;Move Z Axis up little to prevent scratching of Heat Bed\nG1 X70 Y3 Z0.27 F3000 ;Quickly wipe away from the filament line\nG92 E0 ;Reset Extruder" },
"machine_width": { "default_value": 105 },
"material_bed_temperature": { "maximum_value": 60 },
"material_print_temperature": { "maximum_value": 230 },
"retraction_amount": { "value": 2 },
"speed_print":
{
"maximum_value_warning": "200",
"value": 120
},
"speed_topbottom":
{
"maximum_value_warning": "200",
"value": 60
},
"speed_wall":
{
"maximum_value_warning": "200",
"value": 80
},
"speed_wall_0":
{
"maximum_value_warning": "200",
"value": 50
},
"speed_wall_x":
{
"maximum_value_warning": "200",
"value": 80
}
}
}

View file

@ -0,0 +1,59 @@
{
"version": 2,
"name": "Geeetech M1S",
"inherits": "Geeetech_Base_Single_Extruder",
"metadata":
{
"visible": true,
"machine_extruder_trains": { "0": "Geeetech_Single_Extruder" }
},
"overrides":
{
"adhesion_type": { "value": "'brim'" },
"brim_width": { "value": 2 },
"gantry_height": { "value": 35 },
"machine_depth": { "default_value": 105 },
"machine_end_gcode": { "default_value": "G91 ;Switch to relative positioning\nG1 E-2.5 F2700 ;Retract filament\nG1 E-1.5 Z0.2 F2400 ;Retract and raise Z\nG1 X5 Y5 F3000 ;Move away\nG1 Z10 ;lift print head\nG90 ;Switch to absolute positioning\nG28 X Y ;homing XY\nM106 S0 ;off Fan\nM104 S0 ;Cooldown hotend\nM140 S0 ;Cooldown bed\nM84 X Y E ;Disable steppers" },
"machine_head_with_fans_polygon":
{
"default_value": [
[-31, 31],
[34, 31],
[34, -40],
[-31, -40]
]
},
"machine_height": { "default_value": 95 },
"machine_name": { "default_value": "Geeetech M1S" },
"machine_start_gcode": { "default_value": ";Official wiki URL for Geeetech M1S:https://www.geeetech.com/wiki/index.php/Geeetech_M1S_3D_printer \nM104 S{material_print_temperature_layer_0} ; Set Hotend Temperature\nM140 S{material_bed_temperature_layer_0} ; Set Bed Temperature\n;M190 S{material_bed_temperature_layer_0} ; Wait for Bed Temperature\nM109 S{material_print_temperature_layer_0} ; Wait for Hotend Temperature\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nM107 ;Off Fan\nM300 S2500 P1000 ;Play a short tune\nG1 Z0.28 ;Move Z Axis up little to prevent scratching of Heat Bed\nG92 E0 ;Reset Extruder\nG1 Y3 F2400 ;Move to start position\nG1 X75 E40 F500 ;Draw a filament line\nG92 E0 ;Reset Extruder\n;G1 E-0.2 F3000 ;Retract a little\nG1 Z2.0 F3000 ;Move Z Axis up little to prevent scratching of Heat Bed\nG1 X70 Y3 Z0.27 F3000 ;Quickly wipe away from the filament line\nG92 E0 ;Reset Extruder" },
"machine_width": { "default_value": 105 },
"material_bed_temperature": { "maximum_value": 85 },
"material_print_temperature": { "maximum_value": 250 },
"retraction_amount": { "value": 2 },
"speed_print":
{
"maximum_value_warning": "200",
"value": 120
},
"speed_topbottom":
{
"maximum_value_warning": "200",
"value": 60
},
"speed_wall":
{
"maximum_value_warning": "200",
"value": 80
},
"speed_wall_0":
{
"maximum_value_warning": "200",
"value": 50
},
"speed_wall_x":
{
"maximum_value_warning": "200",
"value": 80
}
}
}

View file

@ -81,14 +81,10 @@
"machine_max_jerk_xy": { "value": 45 },
"machine_max_jerk_z": { "value": 0.8 },
"machine_name": { "default_value": "Geeetech Thunder" },
"machine_start_gcode": { "default_value": ";Official viki homepage for Thunder:https://www.geeetech.com/wiki/index.php/Geeetech_Thunder_3D_printer \n\nM104 S{material_print_temperature_layer_0} ; Set Hotend Temperature\nM190 S{material_bed_temperature_layer_0} ; Wait for Bed Temperature\nM109 S{material_print_temperature_layer_0} ; Wait for Hotend Temperature\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nM107 P0 ;Off Main Fan\nM107 P1 ;Off Aux Fan\nM2012 P8 S1 F100 ; ON Light\n;M106 P0 S383 ; ON MainFan 150% if need\n;M106 P1 S255 ; ON Aux Fan 100% if need\nG1 Z5.0 F3000 ;Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0.1 Y20 Z0.8 F5000 ; Move to start position\nG1 X0.1 Y200.0 Z1.2 F1500 E30 ; Draw the first line\nG92 E0 ; Reset Extruder\nG1 X0.4 Y200.0 Z1.2 F3000 ; Move to side a little\nG1 X0.4 Y20 Z1.2 F1500 E25 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.4 F3000.0 ; Scrape off nozzle residue" },
"machine_start_gcode": { "default_value": ";Official wiki URL for Thunder:https://www.geeetech.com/wiki/index.php/Geeetech_Thunder_3D_printer \n\nM104 S{material_print_temperature_layer_0} ; Set Hotend Temperature\nM190 S{material_bed_temperature_layer_0} ; Wait for Bed Temperature\nM109 S{material_print_temperature_layer_0} ; Wait for Hotend Temperature\nG92 E0 ; Reset Extruder\nG28 ; Home all axes\nM107 P0 ;Off Main Fan\nM107 P1 ;Off Aux Fan\nM2012 P8 S1 F100 ; ON Light\n;M106 P0 S383 ; ON MainFan 150% if need\n;M106 P1 S255 ; ON Aux Fan 100% if need\nG1 Z5.0 F3000 ;Move Z Axis up little to prevent scratching of Heat Bed\nG1 X0.1 Y20 Z0.8 F5000 ; Move to start position\nG1 X0.1 Y200.0 Z1.2 F1500 E30 ; Draw the first line\nG92 E0 ; Reset Extruder\nG1 X0.4 Y200.0 Z1.2 F3000 ; Move to side a little\nG1 X0.4 Y20 Z1.2 F1500 E25 ; Draw the second line\nG92 E0 ; Reset Extruder\nG1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed\nG1 X5 Y20 Z0.4 F3000.0 ; Scrape off nozzle residue" },
"machine_width": { "default_value": 250 },
"material_flow_layer_0": { "value": 95 },
"material_print_temperature":
{
"maximum_value": "250",
"value": "200 if speed_infill <=150 else 205 if speed_infill <= 200 else 215 if speed_infill <= 260 else 220"
},
"material_print_temperature": { "maximum_value": "250" },
"material_print_temperature_layer_0":
{
"maximum_value_warning": 300,

View file

@ -21,7 +21,7 @@
0,
5
],
"platform_texture": "hellbot_hidra.png"
"platform_texture": "Hellbot_Hidra_and_Hidra_Plus_V2.png"
},
"overrides":
{

View file

@ -21,7 +21,7 @@
0,
5
],
"platform_texture": "hellbot_hidra_plus.png"
"platform_texture": "Hellbot_Hidra_and_Hidra_Plus_V2.png"
},
"overrides":
{

View file

@ -1,11 +1,11 @@
{
"version": 2,
"name": "Sovol SV01",
"inherits": "sovol_base_bowden",
"inherits": "sovol_base_titan",
"metadata":
{
"visible": true,
"quality_definition": "sovol_base_bowden"
"quality_definition": "sovol_base_titan"
},
"overrides":
{

View file

@ -0,0 +1,25 @@
{
"version": 2,
"name": "Toybox Alpha One/Two",
"inherits": "fdmprinter",
"metadata":
{
"visible": true,
"author": "lukbrew25",
"manufacturer": "Toybox",
"file_formats": "text/x-gcode",
"has_machine_quality": false,
"machine_extruder_trains": { "0": "toybox_alpha_one_two_extruder_0" }
},
"overrides":
{
"gantry_height": { "value": "0.0" },
"machine_depth": { "default_value": 80 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_height": { "default_value": 90 },
"machine_name": { "default_value": "Toybox Alpha One/Two" },
"machine_start_gcode": { "default_value": "G90\nM82" },
"machine_width": { "default_value": 70 },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -48,23 +48,111 @@
"infill_material_flow": { "value": "(1.95-infill_sparse_density / 100 if infill_sparse_density > 95 else 1) * material_flow" },
"infill_overlap": { "value": "0 if infill_sparse_density > 80 else 10" },
"inset_direction": { "value": "'outside_in'" },
"jerk_infill": { "minimum_value_warning": 20 },
"jerk_prime_tower": { "minimum_value_warning": 20 },
"jerk_flooring":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_infill":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_layer_0": { "minimum_value": 1 },
"jerk_prime_tower":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_print":
{
"minimum_value": 1,
"minimum_value_warning": 20,
"value": "20"
},
"jerk_print_layer_0": { "value": "max(20, jerk_wall_0)" },
"jerk_roofing": { "minimum_value_warning": 20 },
"jerk_support": { "minimum_value_warning": 20 },
"jerk_support_infill": { "minimum_value_warning": 20 },
"jerk_support_interface": { "minimum_value_warning": 20 },
"jerk_topbottom": { "minimum_value_warning": 20 },
"jerk_travel": { "value": "jerk_print" },
"jerk_print_layer_0":
{
"minimum_value": 1,
"value": "max(20, jerk_wall_0)"
},
"jerk_roofing":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_skirt_brim": { "minimum_value": 1 },
"jerk_support":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_support_bottom":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_support_infill":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_support_interface":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_support_roof":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_topbottom":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_travel":
{
"minimum_value": 1,
"value": "jerk_print"
},
"jerk_travel_enabled": { "value": false },
"jerk_wall": { "minimum_value_warning": 20 },
"jerk_wall_0": { "minimum_value_warning": 20 },
"jerk_travel_layer_0": { "minimum_value": 1 },
"jerk_wall":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_wall_0":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_wall_0_flooring":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_wall_0_roofing":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_wall_x":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_wall_x_flooring":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"jerk_wall_x_roofing":
{
"minimum_value": 1,
"minimum_value_warning": 20
},
"layer_height": { "value": 0.15 },
"layer_height_0": { "value": "max(0.2, layer_height)" },
"line_width": { "value": "machine_nozzle_size" },

View file

@ -33,12 +33,15 @@
{
"acceleration_enabled":
{
"enabled": false,
"enabled": true,
"value": true
},
"acceleration_infill":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_print"
},
"acceleration_layer_0":
@ -49,11 +52,17 @@
"acceleration_prime_tower":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_print"
},
"acceleration_print":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": 800
},
"acceleration_print_layer_0":
@ -64,32 +73,52 @@
"acceleration_roofing":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_print"
},
"acceleration_skirt_brim":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": 800
},
"acceleration_support":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_print"
},
"acceleration_support_bottom":
{
"enabled": false,
"value": "acceleration_print"
"value": "acceleration_support_interface"
},
"acceleration_support_infill":
{
"enabled": false,
"value": "acceleration_print"
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_support"
},
"acceleration_support_interface":
{
"enabled": false,
"value": "acceleration_print"
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_support"
},
"acceleration_support_roof":
{
"enabled": false,
"value": "acceleration_print"
"value": "acceleration_support_interface"
},
"acceleration_topbottom":
{
@ -99,6 +128,9 @@
"acceleration_travel":
{
"enabled": false,
"maximum_value": 5000,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": 5000
},
"acceleration_travel_enabled":
@ -114,27 +146,36 @@
"acceleration_wall":
{
"enabled": false,
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_print"
},
"acceleration_wall_0":
{
"enabled": false,
"value": "acceleration_print"
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_wall"
},
"acceleration_wall_0_roofing":
{
"enabled": false,
"value": "acceleration_print"
"value": "acceleration_wall"
},
"acceleration_wall_x":
{
"enabled": false,
"value": "acceleration_print"
"maximum_value": 3500,
"minimum_value": 200,
"minimum_value_warning": 750,
"value": "acceleration_wall"
},
"acceleration_wall_x_roofing":
{
"enabled": false,
"value": "acceleration_print"
"value": "acceleration_wall"
},
"adhesion_extruder_nr":
{
@ -203,12 +244,15 @@
"inset_direction": { "value": "'inside_out'" },
"jerk_enabled":
{
"enabled": false,
"enabled": true,
"value": true
},
"jerk_infill":
{
"enabled": false,
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_layer_0":
@ -218,13 +262,19 @@
},
"jerk_prime_tower":
{
"enabled": false,
"enabled": "jerk_enabled and prime_tower_enable and extruders_enabled_count > 1",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_print":
{
"enabled": false,
"value": 6.25
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": 12.5
},
"jerk_print_layer_0":
{
@ -233,33 +283,50 @@
},
"jerk_roofing":
{
"enabled": false,
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_skirt_brim":
{
"enabled": "jerk_enabled and (adhesion_type == 'brim' or adhesion_type == 'skirt')",
"value": 12.5
},
"jerk_support":
{
"enabled": false,
"enabled": "jerk_enabled and support_enable",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_support_bottom":
{
"enabled": false,
"value": "jerk_print"
"value": "jerk_support_interface"
},
"jerk_support_infill":
{
"enabled": false,
"value": "jerk_print"
"enabled": "jerk_enabled and support_enable",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_support"
},
"jerk_support_interface":
{
"enabled": false,
"value": "jerk_print"
"enabled": "jerk_enabled and support_enable",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_support"
},
"jerk_support_roof":
{
"enabled": false,
"value": "jerk_print"
"value": "jerk_support_interface"
},
"jerk_topbottom":
{
@ -268,8 +335,11 @@
},
"jerk_travel":
{
"enabled": false,
"value": "jerk_print"
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": 12.5
},
"jerk_travel_enabled":
{
@ -283,12 +353,18 @@
},
"jerk_wall":
{
"enabled": false,
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_wall_0":
{
"enabled": false,
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_wall_0_roofing":
@ -298,7 +374,10 @@
},
"jerk_wall_x":
{
"enabled": false,
"enabled": "jerk_enabled",
"maximum_value": 35,
"minimum_value": 5,
"minimum_value_warning": 12,
"value": "jerk_print"
},
"jerk_wall_x_roofing":
@ -517,16 +596,86 @@
"skirt_height": { "value": 3 },
"small_skin_width": { "value": 4 },
"speed_equalize_flow_width_factor": { "value": 0 },
"speed_prime_tower": { "value": "speed_topbottom" },
"speed_print": { "value": 50 },
"speed_roofing": { "value": "speed_wall_0" },
"speed_support": { "value": "speed_wall" },
"speed_support_interface": { "value": "speed_topbottom" },
"speed_topbottom": { "value": "speed_wall" },
"speed_infill":
{
"maximum_value": 350,
"maximum_value_warning": 325
},
"speed_prime_tower":
{
"maximum_value": 250,
"maximum_value_warning": 200,
"value": "speed_topbottom"
},
"speed_print":
{
"maximum_value": 350,
"maximum_value_warning": 325,
"value": 50
},
"speed_roofing":
{
"maximum_value": 300,
"maximum_value_warning": 275,
"value": "speed_wall_0"
},
"speed_support":
{
"maximum_value": 350,
"maximum_value_warning": 325,
"value": "speed_wall"
},
"speed_support_infill":
{
"maximum_value": 350,
"maximum_value_warning": 325
},
"speed_support_interface":
{
"maximum_value": 260,
"maximum_value_warning": 255,
"value": "speed_topbottom"
},
"speed_support_roof":
{
"maximum_value": 260,
"maximum_value_warning": 255
},
"speed_topbottom":
{
"maximum_value": 260,
"maximum_value_warning": 255,
"value": "speed_wall"
},
"speed_travel": { "value": 250 },
"speed_wall": { "value": "speed_print * 40/50" },
"speed_wall_0": { "value": "speed_wall * 30/40" },
"speed_wall_x": { "value": "speed_wall" },
"speed_wall":
{
"maximum_value": 260,
"maximum_value_warning": 255,
"value": "speed_print * 40/50"
},
"speed_wall_0":
{
"maximum_value": 260,
"maximum_value_warning": 255,
"value": "speed_wall * 30/40"
},
"speed_wall_0_roofing":
{
"maximum_value": 260,
"maximum_value_warning": 255
},
"speed_wall_x":
{
"maximum_value": 260,
"maximum_value_warning": 255,
"value": "speed_wall"
},
"speed_wall_x_roofing":
{
"maximum_value": 260,
"maximum_value_warning": 255
},
"support_angle": { "value": 40 },
"support_bottom_height": { "value": "2*support_infill_sparse_thickness" },
"support_bottom_line_width":

View file

@ -1,7 +1,7 @@
{
"version": 2,
"name": "Ultimaker Original Dual Extrusion",
"inherits": "ultimaker",
"inherits": "ultimaker_original",
"metadata":
{
"visible": true,
@ -49,10 +49,13 @@
},
"overrides":
{
"cool_fan_speed_0": { "value": "cool_fan_speed_min" },
"gantry_height": { "value": "55" },
"infill_before_walls": { "value": "True" },
"layer_height_0": { "value": "max(0.2, layer_height)" },
"machine_center_is_zero": { "default_value": false },
"machine_depth": { "default_value": 195 },
"machine_end_gcode": { "default_value": "M104 T0 S0 ;1st extruder heater off\nM104 T1 S0 ;2nd extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" },
"machine_end_gcode": { "value": "'M104 T0 S0 ;1st extruder heater off\\nM104 T1 S0 ;2nd extruder heater off' + ('\\nM140 S0 ;heated bed heater off' if machine_heated_bed else '') + '\\nG91 ;relative positioning\\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning'" },
"machine_extruder_count": { "default_value": 2 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_head_with_fans_polygon":
@ -65,9 +68,11 @@
]
},
"machine_height": { "default_value": 200 },
"machine_name": { "default_value": "Ultimaker Original" },
"machine_name": { "default_value": "Ultimaker Original Dual Extrusion" },
"machine_start_gcode": { "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nT1 ;Switch to the 2nd extruder\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F200 E-{switch_extruder_retraction_amount}\nT0 ;Switch to the 1st extruder\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." },
"machine_use_extruder_offset_to_offset_coords": { "default_value": true },
"machine_width": { "default_value": 205 }
"machine_width": { "default_value": 205 },
"material_print_temp_wait": { "value": false },
"speed_slowdown_layers": { "value": 1 }
}
}

View file

@ -72,7 +72,11 @@
"brim_width": { "value": "3" },
"build_volume_temperature": { "maximum_value": 50 },
"cool_fan_speed": { "value": "50" },
"default_material_print_temperature": { "value": "200" },
"default_material_print_temperature":
{
"maximum_value_warning": "320",
"value": "200"
},
"extruder_prime_pos_abs": { "default_value": true },
"gantry_height": { "value": "55" },
"infill_pattern": { "value": "'zigzag' if infill_sparse_density > 80 else 'triangles'" },
@ -104,6 +108,7 @@
"machine_nozzle_heat_up_speed": { "default_value": 1.4 },
"machine_start_gcode": { "default_value": "" },
"machine_width": { "default_value": 330 },
"material_print_temperature_layer_0": { "maximum_value_warning": "320" },
"multiple_mesh_overlap": { "value": "0" },
"optimize_wall_printing_order": { "value": "True" },
"prime_blob_enable":

View file

@ -0,0 +1,51 @@
{
"version": 2,
"name": "UltiMaker S6",
"inherits": "ultimaker_s8",
"metadata":
{
"visible": true,
"author": "UltiMaker",
"manufacturer": "Ultimaker B.V.",
"file_formats": "application/x-ufp;text/x-gcode",
"platform": "ultimaker_s5_platform.obj",
"bom_numbers": [10700, 10701],
"firmware_update_info":
{
"check_urls": [ "https://software.ultimaker.com/releases/firmware/5078167/stable/um-update.swu.version" ],
"id": 5078167,
"update_url": "https://ultimaker.com/firmware?utm_source=cura&utm_medium=software&utm_campaign=fw-update"
},
"first_start_actions": [ "DiscoverUM3Action" ],
"has_machine_quality": true,
"has_materials": true,
"has_variants": true,
"machine_extruder_trains":
{
"0": "ultimaker_s6_extruder_left",
"1": "ultimaker_s6_extruder_right"
},
"nozzle_offsetting_for_disallowed_areas": false,
"platform_offset": [
0,
-30,
-10
],
"platform_texture": "UltimakerS6backplate.png",
"preferred_material": "ultimaker_pla_blue",
"preferred_variant_name": "AA+ 0.4",
"quality_definition": "ultimaker_s8",
"supported_actions": [ "DiscoverUM3Action" ],
"supports_material_export": true,
"supports_network_connection": true,
"supports_usb_connection": false,
"variants_name": "Print Core",
"variants_name_has_translation": true,
"weight": -2
},
"overrides":
{
"adhesion_type": { "value": "'brim'" },
"machine_name": { "default_value": "Ultimaker S6" }
}
}

View file

@ -46,8 +46,6 @@
},
"overrides":
{
"default_material_print_temperature": { "maximum_value_warning": "320" },
"machine_name": { "default_value": "Ultimaker S7" },
"material_print_temperature_layer_0": { "maximum_value_warning": "320" }
"machine_name": { "default_value": "Ultimaker S7" }
}
}

View file

@ -1,7 +1,7 @@
{
"version": 2,
"name": "UltiMaker S8",
"inherits": "ultimaker_s7",
"inherits": "ultimaker_s5",
"metadata":
{
"visible": true,
@ -12,6 +12,17 @@
"bom_numbers": [
10600
],
"exclude_materials": [
"generic_hips",
"generic_flexible",
"generic_cffpps",
"generic_cffpa",
"generic_cffcpe",
"generic_gffpa",
"generic_gffcpe",
"structur3d_",
"ultimaker_ppscf"
],
"firmware_update_info":
{
"check_urls": [ "https://software.ultimaker.com/releases/firmware/10600/stable/um-update.swu.version" ],
@ -37,7 +48,6 @@
"preferred_material": "ultimaker_pla_blue",
"preferred_quality_type": "draft",
"preferred_variant_name": "AA+ 0.4",
"quality_definition": "ultimaker_s8",
"supported_actions": [ "DiscoverUM3Action" ],
"supports_material_export": true,
"supports_network_connection": true,
@ -203,6 +213,14 @@
"unit": "mm/s",
"value": 50
},
"build_volume_temperature":
{
"force_depends_on_settings": [
"support_extruder_nr",
"support_enable"
]
},
"cool_during_extruder_switch": { "value": "'all_fans'" },
"cool_min_layer_time": { "value": 5 },
"cool_min_layer_time_overhang": { "value": 9 },
"cool_min_layer_time_overhang_min_segment_length": { "value": 2 },
@ -245,7 +263,7 @@
{
"maximum_value_warning": "machine_max_jerk_xy / 2",
"unit": "m/s\u00b3",
"value": "jerk_print"
"value": "jerk_wall"
},
"jerk_print":
{
@ -389,6 +407,13 @@
"machine_nozzle_cool_down_speed": { "default_value": 1.3 },
"machine_nozzle_heat_up_speed": { "default_value": 0.6 },
"machine_start_gcode": { "default_value": "M213 U0.1 ;undercut 0.1mm" },
"material_bed_temperature":
{
"force_depends_on_settings": [
"support_extruder_nr",
"support_enable"
]
},
"material_extrusion_cool_down_speed": { "value": 0 },
"material_final_print_temperature": { "value": "material_print_temperature - 5" },
"material_initial_print_temperature": { "value": "material_print_temperature - 5" },
@ -397,6 +422,7 @@
"enabled": true,
"value": 0.5
},
"material_print_temperature": { "maximum_value_warning": 320 },
"material_print_temperature_layer_0": { "maximum_value_warning": 320 },
"max_flow_acceleration": { "value": 8.0 },
"max_skin_angle_for_expansion": { "value": 45 },
@ -412,7 +438,7 @@
"retraction_hop": { "value": 1 },
"retraction_hop_after_extruder_switch_height": { "value": 2 },
"retraction_hop_enabled": { "value": true },
"retraction_min_travel": { "value": "5 if support_enable and support_structure=='tree' else line_width * 2" },
"retraction_min_travel": { "value": "5 if support_enable and support_structure=='tree' else line_width * 2.5" },
"retraction_prime_speed": { "value": 15 },
"skin_edge_support_thickness": { "value": 0 },
"skin_material_flow": { "value": 95 },
@ -445,12 +471,12 @@
"speed_layer_0":
{
"maximum_value_warning": 300,
"value": "speed_wall"
"value": "min(speed_wall, 50)"
},
"speed_prime_tower":
{
"maximum_value_warning": 300,
"value": "speed_wall"
"value": "min(speed_wall, 50)"
},
"speed_print":
{
@ -500,13 +526,13 @@
"speed_travel":
{
"maximum_value": 500,
"maximum_value_warning": 300,
"value": 300
"maximum_value_warning": 500,
"value": 500
},
"speed_travel_layer_0":
{
"maximum_value": 500,
"maximum_value_warning": 300,
"maximum_value_warning": 500,
"value": 150
},
"speed_wall":
@ -556,7 +582,10 @@
"support_roof_height": { "minimum_value_warning": 0 },
"support_structure": { "value": "'normal'" },
"support_top_distance": { "maximum_value_warning": "3*layer_height" },
"support_tree_angle": { "value": 50 },
"support_tree_angle_slow": { "value": 35 },
"support_tree_bp_diameter": { "value": 15 },
"support_tree_branch_diameter": { "value": 8 },
"support_tree_tip_diameter": { "value": 1.0 },
"support_tree_top_rate": { "value": 20 },
"support_xy_distance_overhang": { "value": "machine_nozzle_size" },
@ -573,6 +602,7 @@
"wall_material_flow": { "value": 95 },
"wall_overhang_angle": { "value": 45 },
"wall_x_material_flow": { "value": 100 },
"xy_offset": { "value": 0.05 },
"z_seam_corner": { "value": "'z_seam_corner_weighted'" },
"z_seam_position": { "value": "'backright'" },
"z_seam_type": { "value": "'sharpest_corner'" }

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1 extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X267 F18000\nG1 Y128 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1 extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1 extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S4\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1 extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1",
"position": "1"
},
"overrides":
{
"extruder_nr": { "default_value": 1 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1 extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X267 F18000\nG1 Y128 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1 extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1 extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S4\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1 extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1",
"position": "2"
},
"overrides":
{
"extruder_nr": { "default_value": 2 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1 extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X267 F18000\nG1 Y128 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1 extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1 extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S4\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1 extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1",
"position": "3"
},
"overrides":
{
"extruder_nr": { "default_value": 3 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1 extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X267 F18000\nG1 Y128 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1 extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1 extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S4\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1 extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1mini",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1mini extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X180 F18000\nG1 Y90 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1mini extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1mini extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E5 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1mini extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1mini",
"position": "1"
},
"overrides":
{
"extruder_nr": { "default_value": 1 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1mini extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X180 F18000\nG1 Y90 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1mini extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1mini extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E5 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1mini extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1mini",
"position": "2"
},
"overrides":
{
"extruder_nr": { "default_value": 2 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1mini extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X180 F18000\nG1 Y90 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1mini extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1mini extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E5 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1mini extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,19 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_a1mini",
"position": "3"
},
"overrides":
{
"extruder_nr": { "default_value": 3 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": ";===== A1mini extruder end {extruder_nr} begin =====\nG392 S0\nM1007 S0 ; turn off mass estimation\nM204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X180 F18000\nG1 Y90 F9000\n\nM400\nM106 P1 S0\nM106 P2 S0\n{if material_print_temperature > 142, extruder_nr}\nM104 S{material_print_temperature, extruder_nr}\n{endif}\n\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A0 F{material_flush_purge_speed}\n\nM628 S1\nG92 E0\nG1 E-18 F{material_flush_purge_speed}\nM400\nM629 S1\n\n;===== A1mini extruder end {extruder_nr} finish =====\n" },
"machine_extruder_start_code": { "default_value": ";===== A1mini extruder start {extruder_nr} begin =====\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\nM620.10 A1 F{material_flush_purge_speed} L{material_flush_purge_length} H{machine_nozzle_size} T{material_print_temperature, extruder_nr}\n\nM400\nG92 E0\n\n{if not prime_tower_enable}\n\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n\nM400\nM106 P1 S60\nG1 E5 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n; G1 E-{retraction_amount} F1800\nM400\nM106 P1 S178\nM400 S3\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nG1 X-3.5 F18000\nG1 X-13.5 F3000\nM400\nM106 P1 S0\n\nM622.1 S0\n\nM621 S{extruder_nr}A\nG392 S0\n\nM1007 S1\n;===== A1mini extruder start {extruder_nr} finish =====\n" },
"material_diameter": { "default_value": 1.75 },
"switch_extruder_retraction_amount": { "default_value": 18 }
}
}

View file

@ -0,0 +1,18 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_x1",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": "M204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n\n{if material_print_temperature > 142}\nM104 S{material_print_temperature}\n{endif}\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\nG1 X20 Y50 F21000\nG1 Y-3\n\n;{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n;{endif}\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n" },
"machine_extruder_start_code": { "default_value": "M620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n\nG92 E0\n\n; always use highest temperature to flush\n{if material_type == 'PETG'}\nM109 S260\n{elsif material_type == 'PVA'}\nM109 S210\n{else}\nM109 S{material_print_temperature}\n{endif}\n\n{if not prime_tower_enable}\n\nM83\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; FLUSH_START\nM400\nM109 S{material_print_temperature}\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n;G1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X105 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\n\nG1 X70 F10000\nG1 X80 F15000\nG1 X60\nG1 X80\nG1 X60\nG1 X80 ; shake to put down garbage\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\n\nM621 S{extruder_nr}A\n" },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,18 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_x1",
"position": "1"
},
"overrides":
{
"extruder_nr": { "default_value": 1 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": "M204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n\n{if material_print_temperature > 142}\nM104 S{material_print_temperature}\n{endif}\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\nG1 X20 Y50 F21000\nG1 Y-3\n\n;{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n;{endif}\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n" },
"machine_extruder_start_code": { "default_value": "M620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n\nG92 E0\n\n; always use highest temperature to flush\n{if material_type == 'PETG'}\nM109 S260\n{elsif material_type == 'PVA'}\nM109 S210\n{else}\nM109 S{material_print_temperature}\n{endif}\n\n{if not prime_tower_enable}\n\nM83\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; FLUSH_START\nM400\nM109 S{material_print_temperature}\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n;G1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X105 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\n\nG1 X70 F10000\nG1 X80 F15000\nG1 X60\nG1 X80\nG1 X60\nG1 X80 ; shake to put down garbage\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\n\nM621 S{extruder_nr}A\n" },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,18 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_x1",
"position": "2"
},
"overrides":
{
"extruder_nr": { "default_value": 2 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": "M204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n\n{if material_print_temperature > 142}\nM104 S{material_print_temperature}\n{endif}\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\nG1 X20 Y50 F21000\nG1 Y-3\n\n;{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n;{endif}\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n" },
"machine_extruder_start_code": { "default_value": "M620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n\nG92 E0\n\n; always use highest temperature to flush\n{if material_type == 'PETG'}\nM109 S260\n{elsif material_type == 'PVA'}\nM109 S210\n{else}\nM109 S{material_print_temperature}\n{endif}\n\n{if not prime_tower_enable}\n\nM83\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; FLUSH_START\nM400\nM109 S{material_print_temperature}\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n;G1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X105 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\n\nG1 X70 F10000\nG1 X80 F15000\nG1 X60\nG1 X80\nG1 X60\nG1 X80 ; shake to put down garbage\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\n\nM621 S{extruder_nr}A\n" },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,18 @@
{
"version": 2,
"name": "Extruder",
"inherits": "fdmextruder",
"metadata":
{
"machine": "bambulab_x1",
"position": "3"
},
"overrides":
{
"extruder_nr": { "default_value": 3 },
"machine_extruder_change_duration": { "default_value": 29 },
"machine_extruder_end_code": { "default_value": "M204 S9000\n\nG91 ; set relative positioning\nG1 Z3.0 F1200\nG90 ; back to abolute positioning\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n\n{if material_print_temperature > 142}\nM104 S{material_print_temperature}\n{endif}\n\nM620.11 S1 I{extruder_nr} E-18 F1200\nM400\n\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\nG1 X20 Y50 F21000\nG1 Y-3\n\n;{if toolchange_count == 2}\n; get travel path for change filament\n;M620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\n;M620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\n;M620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n;{endif}\n\nM620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n" },
"machine_extruder_start_code": { "default_value": "M620.1 E F{material_flush_purge_speed} T{material_print_temperature, extruder_nr}\n\nG92 E0\n\n; always use highest temperature to flush\n{if material_type == 'PETG'}\nM109 S260\n{elsif material_type == 'PVA'}\nM109 S210\n{else}\nM109 S{material_print_temperature}\n{endif}\n\n{if not prime_tower_enable}\n\nM83\n; FLUSH_START\n; always use highest temperature to flush\nM400\nM1002 set_filament_type:UNKNOWN\nM109 S{material_print_temperature, extruder_nr}\nM106 P1 S60\nG1 E{material_flush_purge_length / 4.0} F{min(extruderValues('material_flush_purge_speed'))} ; do not need pulsatile flushing for start part\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{min(extruderValues('material_flush_purge_speed'))}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.23} F{material_flush_purge_speed, extruder_nr}\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\nM400\nM1002 set_filament_type:{material_type, extruder_nr}\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; WIPE\nM400\nM106 P1 S178\nM400 S3\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nG1 X-38.2 F18000\nG1 X-48.2 F3000\nM400\nM106 P1 S0\n\nM106 P1 S60\n; FLUSH_START\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\nG1 E{(material_flush_purge_length / 4.0) * 0.18} F{material_flush_purge_speed, extruder_nr}\nG1 E{(material_flush_purge_length / 4.0) * 0.02} F50\n; FLUSH_END\nG1 E-{retraction_amount * 2} F1800\nG1 E{retraction_amount * 2} F300\n\n; FLUSH_START\nM400\nM109 S{material_print_temperature}\nG1 E6 F{material_flush_purge_speed, extruder_nr} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\n\n{endif} ; prime_tower_enable\n\nM400\nG92 E0\n;G1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X105 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\n\nG1 X70 F10000\nG1 X80 F15000\nG1 X60\nG1 X80\nG1 X60\nG1 X80 ; shake to put down garbage\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\n\nM621 S{extruder_nr}A\n" },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,16 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata":
{
"machine": "biqu_b2",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,16 @@
{
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata":
{
"machine": "biqu_b2",
"position": "1"
},
"overrides":
{
"extruder_nr": { "default_value": 1 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,17 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata":
{
"machine": "toybox_alpha_one_two",
"position": "0"
},
"overrides":
{
"extruder_nr": { "default_value": 0 },
"machine_nozzle_offset_x": { "default_value": -3.0 },
"machine_nozzle_size": { "default_value": 0.4 },
"material_diameter": { "default_value": 1.75 }
}
}

View file

@ -0,0 +1,31 @@
{
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata":
{
"machine": "ultimaker_s6",
"position": "0"
},
"overrides":
{
"extruder_nr":
{
"default_value": 0,
"maximum_value": "1"
},
"extruder_prime_pos_x": { "default_value": -3 },
"extruder_prime_pos_y": { "default_value": 6 },
"extruder_prime_pos_z": { "default_value": 2 },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "default_value": 330 },
"machine_extruder_end_pos_y": { "default_value": 237 },
"machine_extruder_start_code": { "value": "\"M214 D0 K{material_pressure_advance_factor} R0.04\"" },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "default_value": 330 },
"machine_extruder_start_pos_y": { "default_value": 237 },
"machine_nozzle_head_distance": { "default_value": 2.7 },
"machine_nozzle_offset_x": { "default_value": 0 },
"machine_nozzle_offset_y": { "default_value": 0 }
}
}

View file

@ -0,0 +1,31 @@
{
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata":
{
"machine": "ultimaker_s6",
"position": "1"
},
"overrides":
{
"extruder_nr":
{
"default_value": 1,
"maximum_value": "1"
},
"extruder_prime_pos_x": { "default_value": 333 },
"extruder_prime_pos_y": { "default_value": 6 },
"extruder_prime_pos_z": { "default_value": 2 },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "default_value": 330 },
"machine_extruder_end_pos_y": { "default_value": 219 },
"machine_extruder_start_code": { "value": "\"M214 D0 K{material_pressure_advance_factor} R0.04\"" },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "default_value": 330 },
"machine_extruder_start_pos_y": { "default_value": 219 },
"machine_nozzle_head_distance": { "default_value": 4.2 },
"machine_nozzle_offset_x": { "default_value": 22 },
"machine_nozzle_offset_y": { "default_value": 0 }
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View file

@ -0,0 +1,32 @@
[general]
definition = ultimaker_methodx
name = High Speed
version = 4
[metadata]
intent_category = highspeed
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1C
[values]
acceleration_print = 3500
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_pattern = zigzag
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag

View file

@ -0,0 +1,38 @@
[general]
definition = ultimaker_methodx
name = High Speed Solid
version = 4
[metadata]
intent_category = highspeedsolid
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1C
[values]
acceleration_print = 3500
bottom_thickness = =top_bottom_thickness
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_angles = [45,135]
infill_material_flow = 97
infill_pattern = zigzag
infill_sparse_density = 99
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag
top_bottom_thickness = =layer_height * 2
top_thickness = =top_bottom_thickness

View file

@ -0,0 +1,32 @@
[general]
definition = ultimaker_methodx
name = High Speed
version = 4
[metadata]
intent_category = highspeed
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1XA
[values]
acceleration_print = 3500
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_pattern = zigzag
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag

View file

@ -0,0 +1,38 @@
[general]
definition = ultimaker_methodx
name = High Speed Solid
version = 4
[metadata]
intent_category = highspeedsolid
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1XA
[values]
acceleration_print = 3500
bottom_thickness = =top_bottom_thickness
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_angles = [45,135]
infill_material_flow = 97
infill_pattern = zigzag
infill_sparse_density = 99
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag
top_bottom_thickness = =layer_height * 2
top_thickness = =top_bottom_thickness

View file

@ -0,0 +1,32 @@
[general]
definition = ultimaker_methodx
name = High Speed
version = 4
[metadata]
intent_category = highspeed
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = LABS
[values]
acceleration_print = 3500
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_pattern = zigzag
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag

View file

@ -0,0 +1,38 @@
[general]
definition = ultimaker_methodx
name = High Speed Solid
version = 4
[metadata]
intent_category = highspeedsolid
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = LABS
[values]
acceleration_print = 3500
bottom_thickness = =top_bottom_thickness
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_angles = [45,135]
infill_material_flow = 97
infill_pattern = zigzag
infill_sparse_density = 99
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag
top_bottom_thickness = =layer_height * 2
top_thickness = =top_bottom_thickness

View file

@ -0,0 +1,32 @@
[general]
definition = ultimaker_methodxl
name = High Speed
version = 4
[metadata]
intent_category = highspeed
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1C
[values]
acceleration_print = 3500
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_pattern = zigzag
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag

View file

@ -0,0 +1,38 @@
[general]
definition = ultimaker_methodxl
name = High Speed Solid
version = 4
[metadata]
intent_category = highspeedsolid
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1C
[values]
acceleration_print = 3500
bottom_thickness = =top_bottom_thickness
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_angles = [45,135]
infill_material_flow = 97
infill_pattern = zigzag
infill_sparse_density = 99
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag
top_bottom_thickness = =layer_height * 2
top_thickness = =top_bottom_thickness

View file

@ -0,0 +1,32 @@
[general]
definition = ultimaker_methodxl
name = High Speed
version = 4
[metadata]
intent_category = highspeed
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1XA
[values]
acceleration_print = 3500
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_pattern = zigzag
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag

View file

@ -0,0 +1,38 @@
[general]
definition = ultimaker_methodxl
name = High Speed Solid
version = 4
[metadata]
intent_category = highspeedsolid
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = 1XA
[values]
acceleration_print = 3500
bottom_thickness = =top_bottom_thickness
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_angles = [45,135]
infill_material_flow = 97
infill_pattern = zigzag
infill_sparse_density = 99
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag
top_bottom_thickness = =layer_height * 2
top_thickness = =top_bottom_thickness

View file

@ -0,0 +1,32 @@
[general]
definition = ultimaker_methodxl
name = High Speed
version = 4
[metadata]
intent_category = highspeed
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = LABS
[values]
acceleration_print = 3500
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_pattern = zigzag
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag

View file

@ -0,0 +1,38 @@
[general]
definition = ultimaker_methodxl
name = High Speed Solid
version = 4
[metadata]
intent_category = highspeedsolid
is_experimental = True
material = ultimaker_absr_175
quality_type = draft
setting_version = 25
type = intent
variant = LABS
[values]
acceleration_print = 3500
bottom_thickness = =top_bottom_thickness
bridge_wall_speed = 300
cool_fan_enabled = True
cool_fan_speed = 100
cool_min_layer_time = 3
cool_min_temperature = 245.0
infill_angles = [45,135]
infill_material_flow = 97
infill_pattern = zigzag
infill_sparse_density = 99
jerk_print = 35
speed_layer_0 = 55
speed_print = 300
speed_support = 100
speed_support_interface = 75
speed_travel = 500
speed_travel_layer_0 = 250
speed_wall_0 = 40
support_pattern = zigzag
top_bottom_thickness = =layer_height * 2
top_thickness = =top_bottom_thickness

View file

@ -14,5 +14,5 @@ variant = AA+ 0.4
[values]
infill_sparse_density = 20
top_bottom_thickness = =wall_thickness
wall_thickness = =line_width * 3
wall_thickness = =line_width * 4

View file

@ -14,5 +14,5 @@ variant = AA+ 0.4
[values]
infill_sparse_density = 20
top_bottom_thickness = =wall_thickness
wall_thickness = =line_width * 3
wall_thickness = =line_width * 4

Some files were not shown because too many files have changed in this diff Show more