From 1aa70748aff3eeaac5b6f41dd07172069d3b67b7 Mon Sep 17 00:00:00 2001 From: ChrisTerBeke Date: Mon, 29 Jul 2019 17:24:10 +0200 Subject: [PATCH] Consistent naming, some bug fixes --- .../Models/DiscoveredPrintersModel.py | 2 +- cura/Settings/GlobalStack.py | 2 +- .../src/Cloud/CloudOutputDeviceManager.py | 59 ++++---- ...OutputDevice.py => NetworkOutputDevice.py} | 2 +- .../src/Network/NetworkOutputDeviceManager.py | 131 ++++++------------ .../UM3NetworkPrinting/src/SendMaterialJob.py | 6 +- 6 files changed, 70 insertions(+), 132 deletions(-) rename plugins/UM3NetworkPrinting/src/Network/{LocalClusterOutputDevice.py => NetworkOutputDevice.py} (99%) diff --git a/cura/Machines/Models/DiscoveredPrintersModel.py b/cura/Machines/Models/DiscoveredPrintersModel.py index 33e0b7a4d9..a1b68ee1ae 100644 --- a/cura/Machines/Models/DiscoveredPrintersModel.py +++ b/cura/Machines/Models/DiscoveredPrintersModel.py @@ -75,7 +75,7 @@ class DiscoveredPrinter(QObject): def readableMachineType(self) -> str: from cura.CuraApplication import CuraApplication machine_manager = CuraApplication.getInstance().getMachineManager() - # In LocalClusterOutputDevice, when it updates a printer information, it updates the machine type using the field + # In NetworkOutputDevice, when it updates a printer information, it updates the machine type using the field # "machine_variant", and for some reason, it's not the machine type ID/codename/... but a human-readable string # like "Ultimaker 3". The code below handles this case. if self._hasHumanReadableMachineTypeName(self._machine_type): diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index 3502088e2d..7efc263180 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -118,7 +118,7 @@ class GlobalStack(CuraContainerStack): ## \sa configuredConnectionTypes def removeConfiguredConnectionType(self, connection_type: int) -> None: configured_connection_types = self.configuredConnectionTypes - if connection_type in self.configured_connection_types: + if connection_type in configured_connection_types: # Store the values as a string. configured_connection_types.remove(connection_type) self.setMetaDataEntry("connection_type", ",".join([str(c_type) for c_type in configured_connection_types])) diff --git a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py index e1e54c2991..2cd3f5a534 100644 --- a/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Cloud/CloudOutputDeviceManager.py @@ -6,7 +6,6 @@ from PyQt5.QtCore import QTimer from UM import i18nCatalog from UM.Logger import Logger -from UM.Message import Message from UM.Signal import Signal from cura.API import Account from cura.CuraApplication import CuraApplication @@ -54,13 +53,32 @@ class CloudOutputDeviceManager: self._running = False + ## Starts running the cloud output device manager, thus periodically requesting cloud data. + def start(self): + if self._running: + return + self._account.loginStateChanged.connect(self._onLoginStateChanged) + # When switching machines we check if we have to activate a remote cluster. + self._application.globalContainerStackChanged.connect(self._connectToActiveMachine) + self._update_timer.timeout.connect(self._getRemoteClusters) + self._onLoginStateChanged(is_logged_in = self._account.isLoggedIn) + + ## Stops running the cloud output device manager. + def stop(self): + if not self._running: + return + self._account.loginStateChanged.disconnect(self._onLoginStateChanged) + # When switching machines we check if we have to activate a remote cluster. + self._application.globalContainerStackChanged.disconnect(self._connectToActiveMachine) + self._update_timer.timeout.disconnect(self._getRemoteClusters) + self._onLoginStateChanged(is_logged_in = False) + ## Force refreshing connections. def refreshConnections(self) -> None: - pass + self._connectToActiveMachine() ## Called when the uses logs in or out def _onLoginStateChanged(self, is_logged_in: bool) -> None: - Logger.log("d", "Log in state changed to %s", is_logged_in) if is_logged_in: if not self._update_timer.isActive(): self._update_timer.start() @@ -74,18 +92,13 @@ class CloudOutputDeviceManager: ## Gets all remote clusters from the API. def _getRemoteClusters(self) -> None: - Logger.log("d", "Retrieving remote clusters") self._api.getClusters(self._onGetRemoteClustersFinished) ## Callback for when the request for getting the clusters. is finished. def _onGetRemoteClustersFinished(self, clusters: List[CloudClusterResponse]) -> None: online_clusters = {c.cluster_id: c for c in clusters if c.is_online} # type: Dict[str, CloudClusterResponse] - removed_devices, added_clusters, updates = findChanges(self._remote_clusters, online_clusters) - Logger.log("d", "Parsed remote clusters to %s", [cluster.toDict() for cluster in online_clusters.values()]) - Logger.log("d", "Removed: %s, added: %s, updates: %s", len(removed_devices), len(added_clusters), len(updates)) - # Remove output devices that are gone for device in removed_devices: if device.isConnected(): @@ -136,12 +149,7 @@ class CloudOutputDeviceManager: # 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) + self._connectToActiveMachine() ## Callback for when the active machine was changed by the user or a new remote cluster was found. def _connectToActiveMachine(self) -> None: @@ -182,31 +190,12 @@ class CloudOutputDeviceManager: ## Connects to an output device and makes sure it is registered in the output device manager. def _connectToOutputDevice(self, device: CloudOutputDevice, active_machine: GlobalStack) -> None: device.connect() - self._output_device_manager.addOutputDevice(device) + active_machine.setMetaDataEntry(self.META_CLUSTER_ID, device.key) active_machine.addConfiguredConnectionType(device.connectionType.value) + self._output_device_manager.addOutputDevice(device) ## Handles an API error received from the cloud. # \param errors: The errors received @staticmethod def _onApiError(errors: List[CloudError] = None) -> None: Logger.log("w", str(errors)) - - ## Starts running the cloud output device manager, thus periodically requesting cloud data. - def start(self): - if self._running: - return - self._account.loginStateChanged.connect(self._onLoginStateChanged) - # When switching machines we check if we have to activate a remote cluster. - self._application.globalContainerStackChanged.connect(self._connectToActiveMachine) - self._update_timer.timeout.connect(self._getRemoteClusters) - self._onLoginStateChanged(is_logged_in = self._account.isLoggedIn) - - ## Stops running the cloud output device manager. - def stop(self): - if not self._running: - return - self._account.loginStateChanged.disconnect(self._onLoginStateChanged) - # When switching machines we check if we have to activate a remote cluster. - self._application.globalContainerStackChanged.disconnect(self._connectToActiveMachine) - self._update_timer.timeout.disconnect(self._getRemoteClusters) - self._onLoginStateChanged(is_logged_in = False) diff --git a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py b/plugins/UM3NetworkPrinting/src/Network/NetworkOutputDevice.py similarity index 99% rename from plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py rename to plugins/UM3NetworkPrinting/src/Network/NetworkOutputDevice.py index ff57719105..523bb8a6af 100644 --- a/plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py +++ b/plugins/UM3NetworkPrinting/src/Network/NetworkOutputDevice.py @@ -20,7 +20,7 @@ from ..UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOut I18N_CATALOG = i18nCatalog("cura") -class LocalClusterOutputDevice(UltimakerNetworkedPrinterOutputDevice): +class NetworkOutputDevice(UltimakerNetworkedPrinterOutputDevice): activeCameraUrlChanged = pyqtSignal() diff --git a/plugins/UM3NetworkPrinting/src/Network/NetworkOutputDeviceManager.py b/plugins/UM3NetworkPrinting/src/Network/NetworkOutputDeviceManager.py index a60fbfa664..9f33439f18 100644 --- a/plugins/UM3NetworkPrinting/src/Network/NetworkOutputDeviceManager.py +++ b/plugins/UM3NetworkPrinting/src/Network/NetworkOutputDeviceManager.py @@ -15,9 +15,10 @@ from UM.Version import Version from cura.CuraApplication import CuraApplication from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice +from cura.Settings.GlobalStack import GlobalStack from .ClusterApiClient import ClusterApiClient -from .LocalClusterOutputDevice import LocalClusterOutputDevice +from .NetworkOutputDevice import NetworkOutputDevice from .ManualPrinterRequest import ManualPrinterRequest @@ -38,9 +39,10 @@ class NetworkOutputDeviceManager: def __init__(self) -> None: # Persistent dict containing the networked clusters. - self._discovered_devices = {} # type: Dict[str, LocalClusterOutputDevice] + self._discovered_devices = {} # type: Dict[str, NetworkOutputDevice] self._output_device_manager = CuraApplication.getInstance().getOutputDeviceManager() + # TODO: move zeroconf stuff to own class self._zero_conf = None # type: Optional[Zeroconf] self._zero_conf_browser = None # type: Optional[ServiceBrowser] self._service_changed_request_queue = None # type: Optional[Queue] @@ -55,30 +57,6 @@ class NetworkOutputDeviceManager: self.addedNetworkCluster.connect(self._onAddDevice) self.removedNetworkCluster.connect(self._onRemoveDevice) - ## Force reset all network device connections. - def refreshConnections(self): - active_machine = CuraApplication.getInstance().getGlobalContainerStack() - if not active_machine: - return - - um_network_key = active_machine.getMetaDataEntry("um_network_key") - for key in self._discovered_devices: - if key == um_network_key: - if not self._discovered_devices[key].isConnected(): - Logger.log("d", "Attempting to connect with [%s]" % key) - # It should already be set, but if it actually connects we know for sure it's supported! - active_machine.addConfiguredConnectionType(self._discovered_devices[key].connectionType.value) - self._discovered_devices[key].connect() - self._discovered_devices[key].connectionStateChanged.connect(self._onDeviceConnectionStateChanged) - else: - self._onDeviceConnectionStateChanged(key) - else: - if self._discovered_devices[key].isConnected(): - Logger.log("d", "Attempting to close connection with [%s]" % key) - self._discovered_devices[key].close() - self._discovered_devices[key].connectionStateChanged.disconnect( - self._onDeviceConnectionStateChanged) - ## Start the network discovery. def start(self): # The ZeroConf service changed requests are handled in a separate thread so we don't block the UI. @@ -145,7 +123,6 @@ class NetworkOutputDeviceManager: if not address: address = self._discovered_devices[key].ipAddress self._onRemoveDevice(key) - # TODO: self.resetLastManualDevice() if address in self._manual_instances: manual_printer_request = self._manual_instances.pop(address) @@ -155,6 +132,33 @@ class NetworkOutputDeviceManager: if manual_printer_request.callback is not None: CuraApplication.getInstance().callLater(manual_printer_request.callback, False, address) + ## Force reset all network device connections. + def refreshConnections(self): + self._connectToActiveMachine() + + ## Callback for when the active machine was changed by the user or a new remote cluster was found. + def _connectToActiveMachine(self): + active_machine = CuraApplication.getInstance().getGlobalContainerStack() + if not active_machine: + return + + for device_id in self._discovered_devices: + CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device_id) + + stored_network_key = active_machine.getMetaDataEntry("um_network_key") + if stored_network_key in self._discovered_devices: + device = self._discovered_devices[stored_network_key] + self._connectToOutputDevice(device, active_machine) + + ## Add a device to the current active machine. + @staticmethod + def _connectToOutputDevice(device: PrinterOutputDevice, active_machine: GlobalStack) -> None: + device.connect() + active_machine.setMetaDataEntry("um_network_key", device.key) + active_machine.setMetaDataEntry("group_name", device.name) + active_machine.addConfiguredConnectionType(device.connectionType.value) + CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device) + ## Handles an API error received from the cloud. # \param errors: The errors received def _onApiError(self, errors) -> None: @@ -212,7 +216,7 @@ class NetworkOutputDeviceManager: if cluster_size == -1: return - device = LocalClusterOutputDevice(key, address, properties) + device = NetworkOutputDevice(key, address, properties) CuraApplication.getInstance().getDiscoveredPrintersModel().addDiscoveredPrinter( ip_address=address, @@ -225,28 +229,17 @@ class NetworkOutputDeviceManager: self._discovered_devices[device.getId()] = device self.discoveredDevicesChanged.emit() - - global_container_stack = CuraApplication.getInstance().getGlobalContainerStack() - if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"): - # Ensure that the configured connection type is set. - CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device) - global_container_stack.addConfiguredConnectionType(device.connectionType.value) - device.connect() - device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged) + self._connectToActiveMachine() ## Remove a device. def _onRemoveDevice(self, device_id: str) -> None: device = self._discovered_devices.pop(device_id, None) - if device: - if device.isConnected(): - device.disconnect() - try: - device.connectionStateChanged.disconnect(self._onDeviceConnectionStateChanged) - except TypeError: - # Disconnect already happened. - pass - CuraApplication.getInstance().getDiscoveredPrintersModel().removeDiscoveredPrinter(device.address) - self.discoveredDevicesChanged.emit() + if not device: + return + if device.isConnected(): + device.disconnect() + CuraApplication.getInstance().getDiscoveredPrintersModel().removeDiscoveredPrinter(device.address) + self.discoveredDevicesChanged.emit() ## Appends a service changed request so later the handling thread will pick it up and processes it. def _appendServiceChangedRequest(self, zeroconf: Zeroconf, service_type, name: str, @@ -285,20 +278,6 @@ class NetworkOutputDeviceManager: for request in reschedule_requests: self._service_changed_request_queue.put(request) - ## Callback handler for when the connection state of a networked device has changed. - def _onDeviceConnectionStateChanged(self, key: str) -> None: - if key not in self._discovered_devices: - return - - if self._discovered_devices[key].isConnected(): - um_network_key = CuraApplication.getInstance().getGlobalContainerStack().getMetaDataEntry("um_network_key") - if key != um_network_key: - return - CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(self._discovered_devices[key]) - # TODO: self.checkCloudFlowIsPossible(None) - else: - CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(key) - ## Handler for zeroConf detection. # Return True or False indicating if the process succeeded. # Note that this function can take over 3 seconds to complete. Be careful calling it from the main thread. @@ -347,48 +326,18 @@ class NetworkOutputDeviceManager: self.removedNetworkCluster.emit(str(name)) return True - def _associateActiveMachineWithPrinterDevice(self, printer_device: Optional[PrinterOutputDevice]) -> None: - if not printer_device: - return - - Logger.log("d", "Attempting to set the network key of the active machine to %s", printer_device.key) - - machine_manager = CuraApplication.getInstance().getMachineManager() - global_container_stack = machine_manager.activeMachine - if not global_container_stack: - return - - for machine in machine_manager.getMachinesInGroup(global_container_stack.getMetaDataEntry("group_id")): - machine.setMetaDataEntry("um_network_key", printer_device.key) - machine.setMetaDataEntry("group_name", printer_device.name) - - # Delete old authentication data. - Logger.log("d", "Removing old authentication id %s for device %s", - global_container_stack.getMetaDataEntry("network_authentication_id", None), printer_device.key) - - machine.removeMetaDataEntry("network_authentication_id") - machine.removeMetaDataEntry("network_authentication_key") - - # Ensure that these containers do know that they are configured for network connection - machine.addConfiguredConnectionType(printer_device.connectionType.value) - ## Create a machine instance based on the discovered network printer. def _createMachineFromDiscoveredPrinter(self, key: str) -> None: discovered_device = self._discovered_devices.get(key) if discovered_device is None: Logger.log("e", "Could not find discovered device with key [%s]", key) return - group_name = discovered_device.getProperty("name") machine_type_id = discovered_device.getProperty("printer_type") Logger.log("i", "Creating machine from network device with key = [%s], group name = [%s], printer type = [%s]", key, group_name, machine_type_id) - CuraApplication.getInstance().getMachineManager().addMachine(machine_type_id, group_name) - # connect the new machine to that network printer - self._associateActiveMachineWithPrinterDevice(discovered_device) - # ensure that the connection states are refreshed. - self.refreshConnections() + self._connectToActiveMachine() ## Load the user-configured manual devices from Cura preferences. def _getStoredManualInstances(self) -> Dict[str, ManualPrinterRequest]: diff --git a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py index 697ba33a6b..50705efa8e 100644 --- a/plugins/UM3NetworkPrinting/src/SendMaterialJob.py +++ b/plugins/UM3NetworkPrinting/src/SendMaterialJob.py @@ -13,7 +13,7 @@ from .Models.ClusterMaterial import ClusterMaterial from .Models.LocalMaterial import LocalMaterial if TYPE_CHECKING: - from .Network.LocalClusterOutputDevice import LocalClusterOutputDevice + from .Network.NetworkOutputDevice import NetworkOutputDevice ## Asynchronous job to send material profiles to the printer. @@ -21,9 +21,9 @@ if TYPE_CHECKING: # This way it won't freeze up the interface while sending those materials. class SendMaterialJob(Job): - def __init__(self, device: "LocalClusterOutputDevice") -> None: + def __init__(self, device: "NetworkOutputDevice") -> None: super().__init__() - self.device = device # type: LocalClusterOutputDevice + self.device = device # type: NetworkOutputDevice ## Send the request to the printer and register a callback def run(self) -> None: