Merge branch 'master' of github.com:Ultimaker/Cura

This commit is contained in:
Jaime van Kessel 2019-04-19 13:58:58 +02:00
commit 9daa78a98f
9 changed files with 102 additions and 40 deletions

View File

@ -214,14 +214,14 @@ class CuraApplication(QtApplication):
self._cura_scene_controller = None
self._machine_error_checker = None
self._machine_settings_manager = MachineSettingsManager(self)
self._machine_settings_manager = MachineSettingsManager(self, parent = self)
self._discovered_printer_model = DiscoveredPrintersModel(self)
self._first_start_machine_actions_model = FirstStartMachineActionsModel(self)
self._welcome_pages_model = WelcomePagesModel(self)
self._add_printer_pages_model = AddPrinterPagesModel(self)
self._whats_new_pages_model = WhatsNewPagesModel(self)
self._text_manager = TextManager(self)
self._discovered_printer_model = DiscoveredPrintersModel(parent = self)
self._first_start_machine_actions_model = FirstStartMachineActionsModel(self, parent = self)
self._welcome_pages_model = WelcomePagesModel(self, parent = self)
self._add_printer_pages_model = AddPrinterPagesModel(self, parent = self)
self._whats_new_pages_model = WhatsNewPagesModel(self, parent = self)
self._text_manager = TextManager(parent = self)
self._quality_profile_drop_down_menu_model = None
self._custom_quality_profile_drop_down_menu_model = None

View File

@ -40,4 +40,4 @@ cmake3 \
-DBUILD_TESTS=ON \
..
make
ctest3 --verbose --output-on-failure -T Test
ctest3 --output-on-failure -T Test

View File

@ -58,6 +58,14 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
# Therefore we create a private signal used to trigger the printersChanged signal.
_clusterPrintersChanged = pyqtSignal()
# Map of Cura Connect machine_variant field to Cura machine types.
# Needed for printer discovery stack creation.
_host_machine_variant_to_machine_type_map = {
"Ultimaker 3": "ultimaker3",
"Ultimaker 3 Extended": "ultimaker3_extended",
"Ultimaker S5": "ultimaker_s5"
}
## Creates a new cloud output device
# \param api_client: The client that will run the API calls
# \param cluster: The device response received from the cloud API.
@ -68,10 +76,10 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
# Because the cloud connection does not off all of these, we manually construct this version here.
# An example of why this is needed is the selection of the compatible file type when exporting the tool path.
properties = {
b"address": b"",
b"name": cluster.host_name.encode() if cluster.host_name else b"",
b"address": cluster.host_internal_ip.encode() if cluster.host_internal_ip else b"",
b"name": cluster.friendly_name.encode() if cluster.friendly_name else b"",
b"firmware_version": cluster.host_version.encode() if cluster.host_version else b"",
b"printer_type": b""
b"cluster_size": b"1" # cloud devices are always clusters of at least one
}
super().__init__(device_id = cluster.cluster_id, address = "",
@ -96,6 +104,7 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
# We keep track of which printer is visible in the monitor page.
self._active_printer = None # type: Optional[PrinterOutputModel]
self._host_machine_type = ""
# Properties to populate later on with received cloud data.
self._print_jobs = [] # type: List[UM3PrintJobOutputModel]
@ -236,6 +245,10 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
previous = {p.key: p for p in self._printers} # type: Dict[str, PrinterOutputModel]
received = {p.uuid: p for p in printers} # type: Dict[str, CloudClusterPrinterStatus]
if len(printers) > 0:
# We need the machine type of the host (1st list entry) to allow discovery to work.
self._host_machine_type = printers[0].machine_variant
removed_printers, added_printers, updated_printers = findChanges(previous, received)
for removed_printer in removed_printers:
@ -359,6 +372,19 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
).show()
self.writeFinished.emit()
## Gets the printer type of the cluster host. Falls back to the printer type in the device properties.
@pyqtProperty(str, notify=_clusterPrintersChanged)
def printerType(self) -> str:
if self._printers and self._host_machine_type in self._host_machine_variant_to_machine_type_map:
return self._host_machine_variant_to_machine_type_map[self._host_machine_type]
return super().printerType
## Gets the number of printers in the cluster.
# We use a minimum of 1 because cloud devices are always a cluster and printer discovery needs it.
@pyqtProperty(int, notify = _clusterPrintersChanged)
def clusterSize(self) -> int:
return max(1, len(self._printers))
## Gets the remote printers.
@pyqtProperty("QVariantList", notify=_clusterPrintersChanged)
def printers(self) -> List[PrinterOutputModel]:
@ -376,10 +402,6 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
self._active_printer = printer
self.activePrinterChanged.emit()
@pyqtProperty(int, notify = _clusterPrintersChanged)
def clusterSize(self) -> int:
return len(self._printers)
## Get remote print jobs.
@pyqtProperty("QVariantList", notify = printJobsChanged)
def printJobs(self) -> List[UM3PrintJobOutputModel]:

View File

@ -7,7 +7,7 @@ from PyQt5.QtCore import QTimer
from UM import i18nCatalog
from UM.Logger import Logger
from UM.Message import Message
from UM.Signal import Signal, signalemitter
from UM.Signal import Signal
from cura.API import Account
from cura.CuraApplication import CuraApplication
from cura.Settings.GlobalStack import GlobalStack
@ -81,25 +81,61 @@ class CloudOutputDeviceManager:
Logger.log("d", "Removed: %s, added: %s, updates: %s", len(removed_devices), len(added_clusters), len(updates))
# Remove output devices that are gone
for removed_cluster in removed_devices:
if removed_cluster.isConnected():
removed_cluster.disconnect()
removed_cluster.close()
self._output_device_manager.removeOutputDevice(removed_cluster.key)
self.removedCloudCluster.emit(removed_cluster)
del self._remote_clusters[removed_cluster.key]
for device in removed_devices:
if device.isConnected():
device.disconnect()
device.close()
self._output_device_manager.removeOutputDevice(device.key)
self._application.getDiscoveredPrintersModel().removeDiscoveredPrinter(device.key)
self.removedCloudCluster.emit(device)
del self._remote_clusters[device.key]
# Add an output device for each new remote cluster.
# We only add when is_online as we don't want the option in the drop down if the cluster is not online.
for added_cluster in added_clusters:
device = CloudOutputDevice(self._api, added_cluster)
self._remote_clusters[added_cluster.cluster_id] = device
self.addedCloudCluster.emit(added_cluster)
for cluster in added_clusters:
device = CloudOutputDevice(self._api, cluster)
self._remote_clusters[cluster.cluster_id] = device
self._application.getDiscoveredPrintersModel().addDiscoveredPrinter(
cluster.cluster_id,
device.key,
cluster.friendly_name,
self._createMachineFromDiscoveredPrinter,
device.printerType,
device
)
self.addedCloudCluster.emit(cluster)
# Update the output devices
for device, cluster in updates:
device.clusterData = cluster
self._application.getDiscoveredPrintersModel().updateDiscoveredPrinter(
cluster.cluster_id,
cluster.friendly_name,
device.printerType,
)
self._connectToActiveMachine()
def _createMachineFromDiscoveredPrinter(self, key: str) -> None:
device = self._remote_clusters[key] # type: CloudOutputDevice
if not device:
Logger.log("e", "Could not find discovered device with key [%s]", key)
return
group_name = device.clusterData.friendly_name
machine_type_id = device.printerType
Logger.log("i", "Creating machine from cloud device with key = [%s], group name = [%s], printer type = [%s]",
key, group_name, machine_type_id)
# The newly added machine is automatically activated.
self._application.getMachineManager().addMachine(machine_type_id, group_name)
active_machine = CuraApplication.getInstance().getGlobalContainerStack()
if not active_machine:
return
active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key)
self._connectToOutputDevice(device, active_machine)
## Callback for when the active machine was changed by the user or a new remote cluster was found.
def _connectToActiveMachine(self) -> None:

View File

@ -16,7 +16,8 @@ class CloudClusterResponse(BaseCloudModel):
# \param status: The status of the cluster authentication (active or inactive).
# \param host_version: The firmware version of the cluster host. This is where the Stardust client is running on.
def __init__(self, cluster_id: str, host_guid: str, host_name: str, is_online: bool, status: str,
host_internal_ip: Optional[str] = None, host_version: Optional[str] = None, **kwargs) -> None:
host_internal_ip: Optional[str] = None, host_version: Optional[str] = None,
friendly_name: Optional[str] = None, **kwargs) -> None:
self.cluster_id = cluster_id
self.host_guid = host_guid
self.host_name = host_name
@ -24,6 +25,7 @@ class CloudClusterResponse(BaseCloudModel):
self.is_online = is_online
self.host_version = host_version
self.host_internal_ip = host_internal_ip
self.friendly_name = friendly_name
super().__init__(**kwargs)
# Validates the model, raising an exception if the model is invalid.

View File

@ -22,6 +22,7 @@ class TestCloudOutputDevice(TestCase):
HOST_NAME = "ultimakersystem-ccbdd30044ec"
HOST_GUID = "e90ae0ac-1257-4403-91ee-a44c9b7e8050"
HOST_VERSION = "5.2.0"
FRIENDLY_NAME = "My Friendly Printer"
STATUS_URL = "{}/connect/v1/clusters/{}/status".format(CuraCloudAPIRoot, CLUSTER_ID)
PRINT_URL = "{}/connect/v1/clusters/{}/print/{}".format(CuraCloudAPIRoot, CLUSTER_ID, JOB_ID)
@ -37,7 +38,8 @@ class TestCloudOutputDevice(TestCase):
patched_method.start()
self.cluster = CloudClusterResponse(self.CLUSTER_ID, self.HOST_GUID, self.HOST_NAME, is_online=True,
status="active", host_version=self.HOST_VERSION)
status="active", host_version=self.HOST_VERSION,
friendly_name=self.FRIENDLY_NAME)
self.network = NetworkManagerMock()
self.account = MagicMock(isLoggedIn=True, accessToken="TestAccessToken")
@ -60,7 +62,7 @@ class TestCloudOutputDevice(TestCase):
# We test for these in order to make sure the correct file type is selected depending on the firmware version.
def test_properties(self):
self.assertEqual(self.device.firmwareVersion, self.HOST_VERSION)
self.assertEqual(self.device.name, self.HOST_NAME)
self.assertEqual(self.device.name, self.FRIENDLY_NAME)
def test_status(self):
self.device._update()

View File

@ -5853,10 +5853,10 @@
"description": "The minimum size of a line segment after slicing. If you increase this, the mesh will have a lower resolution. This may allow the printer to keep up with the speed it has to process g-code and will increase slice speed by removing details of the mesh that it can't process anyway.",
"type": "float",
"unit": "mm",
"default_value": 0.20,
"default_value": 0.5,
"minimum_value": "0.001",
"minimum_value_warning": "0.02",
"maximum_value_warning": "2",
"minimum_value_warning": "0.01",
"maximum_value_warning": "3",
"settable_per_mesh": true
},
"meshfix_maximum_travel_resolution":
@ -5865,8 +5865,8 @@
"description": "The minimum size of a travel line segment after slicing. If you increase this, the travel moves will have less smooth corners. This may allow the printer to keep up with the speed it has to process g-code, but it may cause model avoidance to become less accurate.",
"type": "float",
"unit": "mm",
"default_value": 0.5,
"value": "meshfix_maximum_resolution * speed_travel / speed_print",
"default_value": 1.0,
"value": "min(meshfix_maximum_resolution * speed_travel / speed_print, 2 * line_width)",
"minimum_value": "0.001",
"minimum_value_warning": "0.05",
"maximum_value_warning": "10",
@ -5879,10 +5879,10 @@
"description": "The maximum deviation allowed when reducing the resolution for the Maximum Resolution setting. If you increase this, the print will be less accurate, but the g-code will be smaller.",
"type": "float",
"unit": "mm",
"default_value": 0.005,
"default_value": 0.05,
"minimum_value": "0.001",
"minimum_value_warning": "0.003",
"maximum_value_warning": "0.1",
"minimum_value_warning": "0.01",
"maximum_value_warning": "0.3",
"settable_per_mesh": true
},
"support_skip_some_zags":

View File

@ -118,7 +118,6 @@
"material_bed_temperature": { "maximum_value": "115" },
"material_bed_temperature_layer_0": { "maximum_value": "115" },
"material_standby_temperature": { "value": "100" },
"meshfix_maximum_resolution": { "value": "0.04" },
"multiple_mesh_overlap": { "value": "0" },
"optimize_wall_printing_order": { "value": "True" },
"prime_tower_enable": { "default_value": true },

View File

@ -156,7 +156,8 @@
"wall_0_inset": { "value": "0" },
"wall_line_width_x": { "value": "round(line_width * 0.3 / 0.35, 2)" },
"wall_thickness": { "value": "1" },
"meshfix_maximum_resolution": { "value": "0.04" },
"meshfix_maximum_resolution": { "value": "(speed_wall_0 + speed_wall_x) / 60" },
"meshfix_maximum_deviation": { "value": "layer_height / 2" },
"optimize_wall_printing_order": { "value": "True" },
"retraction_combing": { "default_value": "all" },
"initial_layer_line_width_factor": { "value": "120" },