mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-07 15:07:28 -06:00
Merge branch 'STAR-322_cloud-connection' of github.com:Ultimaker/Cura into STAR-322_cloud-connection
This commit is contained in:
commit
54744b46a7
11 changed files with 123 additions and 32 deletions
|
@ -527,6 +527,12 @@ class MachineManager(QObject):
|
||||||
return self._global_container_stack.getMetaDataEntry("um_network_key", "")
|
return self._global_container_stack.getMetaDataEntry("um_network_key", "")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify=printerConnectedStatusChanged)
|
||||||
|
def activeMachineCloudKey(self) -> str:
|
||||||
|
if self._global_container_stack:
|
||||||
|
return self._global_container_stack.getMetaDataEntry("um_cloud_cluster_id", "")
|
||||||
|
return ""
|
||||||
|
|
||||||
@pyqtProperty(str, notify = printerConnectedStatusChanged)
|
@pyqtProperty(str, notify = printerConnectedStatusChanged)
|
||||||
def activeMachineNetworkGroupName(self) -> str:
|
def activeMachineNetworkGroupName(self) -> str:
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
|
|
|
@ -288,8 +288,10 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
||||||
for updated_job_id in set(current_jobs).intersection(remote_jobs):
|
for updated_job_id in set(current_jobs).intersection(remote_jobs):
|
||||||
self._updateUM3PrintJobOutputModel(current_jobs[updated_job_id], remote_jobs[updated_job_id])
|
self._updateUM3PrintJobOutputModel(current_jobs[updated_job_id], remote_jobs[updated_job_id])
|
||||||
|
|
||||||
# TODO: properly handle removed and updated printers
|
# We only have to update when jobs are added or removed
|
||||||
self.printJobsChanged.emit()
|
# updated jobs push their changes via their outputmodel
|
||||||
|
if len(removed_job_ids) > 0 or len(new_job_ids) > 0:
|
||||||
|
self.printJobsChanged.emit()
|
||||||
|
|
||||||
def _addPrintJob(self, job: CloudClusterPrintJob) -> None:
|
def _addPrintJob(self, job: CloudClusterPrintJob) -> None:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
from threading import Timer
|
from typing import Dict, List, Optional
|
||||||
from typing import Dict, List
|
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
|
|
||||||
from UM import i18nCatalog
|
from UM import i18nCatalog
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
@ -9,7 +10,6 @@ from UM.Message import Message
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient import CloudApiClient
|
from plugins.UM3NetworkPrinting.src.Cloud.CloudApiClient import CloudApiClient
|
||||||
|
|
||||||
from .CloudOutputDevice import CloudOutputDevice
|
from .CloudOutputDevice import CloudOutputDevice
|
||||||
from .Models import CloudCluster, CloudErrorObject
|
from .Models import CloudCluster, CloudErrorObject
|
||||||
|
|
||||||
|
@ -39,23 +39,27 @@ class CloudOutputDeviceManager:
|
||||||
self._account = application.getCuraAPI().account
|
self._account = application.getCuraAPI().account
|
||||||
self._account.loginStateChanged.connect(self._getRemoteClusters)
|
self._account.loginStateChanged.connect(self._getRemoteClusters)
|
||||||
self._api = CloudApiClient(self._account, self._onApiError)
|
self._api = CloudApiClient(self._account, self._onApiError)
|
||||||
|
|
||||||
# When switching machines we check if we have to activate a remote cluster.
|
# When switching machines we check if we have to activate a remote cluster.
|
||||||
application.globalContainerStackChanged.connect(self._connectToActiveMachine)
|
application.globalContainerStackChanged.connect(self._connectToActiveMachine)
|
||||||
|
|
||||||
self._on_cluster_received = Signal()
|
self._on_cluster_received = Signal()
|
||||||
self._on_cluster_received.connect(self._getRemoteClusters)
|
self._on_cluster_received.connect(self._getRemoteClusters)
|
||||||
|
|
||||||
|
self.update_timer = QTimer(CuraApplication.getInstance())
|
||||||
|
self.update_timer.setInterval(self.CHECK_CLUSTER_INTERVAL * 1000)
|
||||||
|
self.update_timer.setSingleShot(False)
|
||||||
|
self.update_timer.timeout.connect(self._on_cluster_received.emit)
|
||||||
|
|
||||||
## Gets all remote clusters from the API.
|
## Gets all remote clusters from the API.
|
||||||
def _getRemoteClusters(self) -> None:
|
def _getRemoteClusters(self) -> None:
|
||||||
Logger.log("i", "Retrieving remote clusters")
|
Logger.log("i", "Retrieving remote clusters")
|
||||||
if self._account.isLoggedIn:
|
if self._account.isLoggedIn:
|
||||||
self._api.getClusters(self._onGetRemoteClustersFinished)
|
self._api.getClusters(self._onGetRemoteClustersFinished)
|
||||||
|
|
||||||
# Only start the polling thread after the user is authenticated
|
# Only start the polling timer after the user is authenticated
|
||||||
# The first call to _getRemoteClusters comes from self._account.loginStateChanged
|
# The first call to _getRemoteClusters comes from self._account.loginStateChanged
|
||||||
timer = Timer(5.0, self._on_cluster_received.emit)
|
self.update_timer.start()
|
||||||
timer.start()
|
|
||||||
|
|
||||||
## Callback for when the request for getting the clusters. is finished.
|
## Callback for when the request for getting the clusters. is finished.
|
||||||
def _onGetRemoteClustersFinished(self, clusters: List[CloudCluster]) -> None:
|
def _onGetRemoteClustersFinished(self, clusters: List[CloudCluster]) -> None:
|
||||||
|
@ -85,7 +89,7 @@ class CloudOutputDeviceManager:
|
||||||
self._output_device_manager.addOutputDevice(device)
|
self._output_device_manager.addOutputDevice(device)
|
||||||
self._remote_clusters[cluster.cluster_id] = device
|
self._remote_clusters[cluster.cluster_id] = device
|
||||||
device.connect() # TODO: remove this
|
device.connect() # TODO: remove this
|
||||||
self._connectToActiveMachine()
|
self._connectToActiveMachine(cluster.cluster_id, cluster.host_name)
|
||||||
|
|
||||||
## Remove a CloudOutputDevice
|
## Remove a CloudOutputDevice
|
||||||
# \param cluster: The cluster that was removed
|
# \param cluster: The cluster that was removed
|
||||||
|
@ -94,11 +98,16 @@ class CloudOutputDeviceManager:
|
||||||
del self._remote_clusters[cluster.cluster_id]
|
del self._remote_clusters[cluster.cluster_id]
|
||||||
|
|
||||||
## Callback for when the active machine was changed by the user.
|
## Callback for when the active machine was changed by the user.
|
||||||
def _connectToActiveMachine(self) -> None:
|
def _connectToActiveMachine(self, cluster_id: Optional[str] = None, host_name: Optional[str] = None) -> None:
|
||||||
active_machine = CuraApplication.getInstance().getGlobalContainerStack()
|
active_machine = CuraApplication.getInstance().getGlobalContainerStack()
|
||||||
if not active_machine:
|
if not active_machine:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# TODO: Remove this once correct pairing has been added (see below).
|
||||||
|
if cluster_id:
|
||||||
|
active_machine.setMetaDataEntry("um_cloud_cluster_id", cluster_id)
|
||||||
|
active_machine.setMetaDataEntry("connect_group_name", host_name)
|
||||||
|
|
||||||
# Check if the stored cluster_id for the active machine is in our list of remote clusters.
|
# Check if the stored cluster_id for the active machine is in our list of remote clusters.
|
||||||
stored_cluster_id = active_machine.getMetaDataEntry("um_cloud_cluster_id")
|
stored_cluster_id = active_machine.getMetaDataEntry("um_cloud_cluster_id")
|
||||||
if stored_cluster_id in self._remote_clusters.keys():
|
if stored_cluster_id in self._remote_clusters.keys():
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"author": "Samuel Pinches",
|
"author": "Samuel Pinches",
|
||||||
"manufacturer": "Alfawise",
|
"manufacturer": "Alfawise",
|
||||||
"file_formats": "text/x-gcode",
|
"file_formats": "text/x-gcode",
|
||||||
"preferred_quality_type": "fine",
|
"preferred_quality_type": "fast",
|
||||||
"machine_extruder_trains":
|
"machine_extruder_trains":
|
||||||
{
|
{
|
||||||
"0": "alfawise_u20_extruder_0"
|
"0": "alfawise_u20_extruder_0"
|
||||||
|
@ -53,9 +53,6 @@
|
||||||
"material_bed_temperature": {
|
"material_bed_temperature": {
|
||||||
"default_value": 50
|
"default_value": 50
|
||||||
},
|
},
|
||||||
"layer_height": {
|
|
||||||
"default_value": 0.15
|
|
||||||
},
|
|
||||||
"layer_height_0": {
|
"layer_height_0": {
|
||||||
"default_value": 0.2
|
"default_value": 0.2
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"author": "Samuel Pinches",
|
"author": "Samuel Pinches",
|
||||||
"manufacturer": "JGAurora",
|
"manufacturer": "JGAurora",
|
||||||
"file_formats": "text/x-gcode",
|
"file_formats": "text/x-gcode",
|
||||||
"preferred_quality_type": "fine",
|
"preferred_quality_type": "fast",
|
||||||
"machine_extruder_trains":
|
"machine_extruder_trains":
|
||||||
{
|
{
|
||||||
"0": "jgaurora_a1_extruder_0"
|
"0": "jgaurora_a1_extruder_0"
|
||||||
|
@ -53,9 +53,6 @@
|
||||||
"material_bed_temperature": {
|
"material_bed_temperature": {
|
||||||
"default_value": 67
|
"default_value": 67
|
||||||
},
|
},
|
||||||
"layer_height": {
|
|
||||||
"default_value": 0.15
|
|
||||||
},
|
|
||||||
"layer_height_0": {
|
"layer_height_0": {
|
||||||
"default_value": 0.12
|
"default_value": 0.12
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"file_formats": "text/x-gcode",
|
"file_formats": "text/x-gcode",
|
||||||
"platform": "jgaurora_a5.stl",
|
"platform": "jgaurora_a5.stl",
|
||||||
"platform_offset": [-242, -101, 273],
|
"platform_offset": [-242, -101, 273],
|
||||||
"preferred_quality_type": "fine",
|
"preferred_quality_type": "fast",
|
||||||
"machine_extruder_trains":
|
"machine_extruder_trains":
|
||||||
{
|
{
|
||||||
"0": "jgaurora_a5_extruder_0"
|
"0": "jgaurora_a5_extruder_0"
|
||||||
|
@ -55,9 +55,6 @@
|
||||||
"material_bed_temperature": {
|
"material_bed_temperature": {
|
||||||
"default_value": 67
|
"default_value": 67
|
||||||
},
|
},
|
||||||
"layer_height": {
|
|
||||||
"default_value": 0.15
|
|
||||||
},
|
|
||||||
"layer_height_0": {
|
"layer_height_0": {
|
||||||
"default_value": 0.12
|
"default_value": 0.12
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"author": "Samuel Pinches",
|
"author": "Samuel Pinches",
|
||||||
"manufacturer": "JGAurora",
|
"manufacturer": "JGAurora",
|
||||||
"file_formats": "text/x-gcode",
|
"file_formats": "text/x-gcode",
|
||||||
"preferred_quality_type": "fine",
|
"preferred_quality_type": "fast",
|
||||||
"machine_extruder_trains":
|
"machine_extruder_trains":
|
||||||
{
|
{
|
||||||
"0": "jgaurora_z_603s_extruder_0"
|
"0": "jgaurora_z_603s_extruder_0"
|
||||||
|
@ -53,9 +53,6 @@
|
||||||
"material_bed_temperature": {
|
"material_bed_temperature": {
|
||||||
"default_value": 55
|
"default_value": 55
|
||||||
},
|
},
|
||||||
"layer_height": {
|
|
||||||
"default_value": 0.15
|
|
||||||
},
|
|
||||||
"layer_height_0": {
|
"layer_height_0": {
|
||||||
"default_value": 0.2
|
"default_value": 0.2
|
||||||
},
|
},
|
||||||
|
|
26
resources/qml/Menus/CloudPrinterMenu.qml
Normal file
26
resources/qml/Menus/CloudPrinterMenu.qml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright (c) 2018 Ultimaker B.V.
|
||||||
|
// Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
import QtQuick 2.2
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
|
import UM 1.2 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
|
||||||
|
Instantiator {
|
||||||
|
|
||||||
|
model: UM.ContainerStacksModel {
|
||||||
|
filter: {"type": "machine", "um_cloud_cluster_id": "*"}
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
// iconSource: UM.Theme.getIcon("printer_single") TODO: use cloud icon here
|
||||||
|
text: model.metadata["connect_group_name"]
|
||||||
|
checkable: true
|
||||||
|
checked: true // cloud printers are only listed if they are actually online
|
||||||
|
exclusiveGroup: group;
|
||||||
|
onTriggered: Cura.MachineManager.setActiveMachine(model.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
onObjectAdded: menu.insertItem(index, object)
|
||||||
|
onObjectRemoved: menu.removeItem(object)
|
||||||
|
}
|
|
@ -37,6 +37,23 @@ Menu
|
||||||
visible: networkPrinterMenu.count > 0
|
visible: networkPrinterMenu.count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@label:category menu label", "Cloud enabled printers")
|
||||||
|
enabled: false
|
||||||
|
visible: cloudPrinterMenu.count > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
CloudPrinterMenu
|
||||||
|
{
|
||||||
|
id: cloudPrinterMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSeparator
|
||||||
|
{
|
||||||
|
visible: cloudPrinterMenu.count > 0
|
||||||
|
}
|
||||||
|
|
||||||
MenuItem
|
MenuItem
|
||||||
{
|
{
|
||||||
text: catalog.i18nc("@label:category menu label", "Local printers")
|
text: catalog.i18nc("@label:category menu label", "Local printers")
|
||||||
|
|
|
@ -115,15 +115,16 @@ UM.PreferencesPage
|
||||||
|
|
||||||
currentIndex:
|
currentIndex:
|
||||||
{
|
{
|
||||||
|
var idx = -1;
|
||||||
for(var i = 0; i < settingVisibilityPresetsModel.items.length; ++i)
|
for(var i = 0; i < settingVisibilityPresetsModel.items.length; ++i)
|
||||||
{
|
{
|
||||||
if(settingVisibilityPresetsModel.items[i].presetId == settingVisibilityPresetsModel.activePreset)
|
if(settingVisibilityPresetsModel.items[i].presetId == settingVisibilityPresetsModel.activePreset)
|
||||||
{
|
{
|
||||||
currentIndex = i;
|
idx = i;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated:
|
onActivated:
|
||||||
|
|
|
@ -50,6 +50,46 @@ Column
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@label", "Cloud connected printers")
|
||||||
|
visible: cloudPrintersModel.items.length > 0
|
||||||
|
leftPadding: UM.Theme.getSize("default_margin").width
|
||||||
|
height: visible ? contentHeight + 2 * UM.Theme.getSize("default_margin").height : 0
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
font: UM.Theme.getFont("medium")
|
||||||
|
color: UM.Theme.getColor("text_medium")
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater
|
||||||
|
{
|
||||||
|
id: cloudPrinters
|
||||||
|
|
||||||
|
model: UM.ContainerStacksModel
|
||||||
|
{
|
||||||
|
id: cloudPrintersModel
|
||||||
|
filter:
|
||||||
|
{
|
||||||
|
"type": "machine",
|
||||||
|
"um_cloud_cluster_id": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: MachineSelectorButton
|
||||||
|
{
|
||||||
|
text: model.metadata["connect_group_name"]
|
||||||
|
checked: Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
|
||||||
|
outputDevice: Cura.MachineManager.printerOutputDevices.length >= 1 ? Cura.MachineManager.printerOutputDevices[0] : null
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: Cura.MachineManager
|
||||||
|
onActiveMachineNetworkGroupNameChanged: checked = Cura.MachineManager.activeMachineNetworkGroupName == model.metadata["connect_group_name"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
text: catalog.i18nc("@label", "Preset printers")
|
text: catalog.i18nc("@label", "Preset printers")
|
||||||
|
@ -71,7 +111,9 @@ Column
|
||||||
id: virtualPrintersModel
|
id: virtualPrintersModel
|
||||||
filter:
|
filter:
|
||||||
{
|
{
|
||||||
"type": "machine", "um_network_key": null
|
"type": "machine",
|
||||||
|
"um_network_key": null,
|
||||||
|
"um_cloud_cluster_id": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue