mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-10 08:17:49 -06:00
Fix adding by manual IP, code improvements
This commit is contained in:
parent
ac177659e5
commit
8a2e394abc
4 changed files with 73 additions and 36 deletions
|
@ -35,6 +35,9 @@ class CloudApiClient:
|
||||||
CLUSTER_API_ROOT = "{}/connect/v1".format(ROOT_PATH)
|
CLUSTER_API_ROOT = "{}/connect/v1".format(ROOT_PATH)
|
||||||
CURA_API_ROOT = "{}/cura/v1".format(ROOT_PATH)
|
CURA_API_ROOT = "{}/cura/v1".format(ROOT_PATH)
|
||||||
|
|
||||||
|
# In order to avoid garbage collection we keep the callbacks in this list.
|
||||||
|
_anti_gc_callbacks = [] # type: List[Callable[[], None]]
|
||||||
|
|
||||||
## Initializes a new cloud API client.
|
## Initializes a new cloud API client.
|
||||||
# \param account: The user's account object
|
# \param account: The user's account object
|
||||||
# \param on_error: The callback to be called whenever we receive errors from the server.
|
# \param on_error: The callback to be called whenever we receive errors from the server.
|
||||||
|
@ -44,8 +47,6 @@ class CloudApiClient:
|
||||||
self._account = account
|
self._account = account
|
||||||
self._on_error = on_error
|
self._on_error = on_error
|
||||||
self._upload = None # type: Optional[ToolPathUploader]
|
self._upload = None # type: Optional[ToolPathUploader]
|
||||||
# In order to avoid garbage collection we keep the callbacks in this list.
|
|
||||||
self._anti_gc_callbacks = [] # type: List[Callable[[], None]]
|
|
||||||
|
|
||||||
## Gets the account used for the API.
|
## Gets the account used for the API.
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from UM import i18nCatalog
|
||||||
|
from UM.Message import Message
|
||||||
|
|
||||||
|
|
||||||
|
I18N_CATALOG = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
|
## Message shown when uploading a print job to a cluster is blocked because another upload is already in progress.
|
||||||
|
class LegacyDeviceNoLongerSupportedMessage(Message):
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__(
|
||||||
|
text = I18N_CATALOG.i18nc("@info:status", "You are attempting to connect to a printer that is not "
|
||||||
|
"running Ultimaker Connect. Please update the printer to the "
|
||||||
|
"latest firmware."),
|
||||||
|
title = I18N_CATALOG.i18nc("@info:title", "Update your printer"),
|
||||||
|
lifetime = 10
|
||||||
|
)
|
|
@ -25,6 +25,9 @@ class ClusterApiClient:
|
||||||
PRINTER_API_PREFIX = "/api/v1"
|
PRINTER_API_PREFIX = "/api/v1"
|
||||||
CLUSTER_API_PREFIX = "/cluster-api/v1"
|
CLUSTER_API_PREFIX = "/cluster-api/v1"
|
||||||
|
|
||||||
|
# In order to avoid garbage collection we keep the callbacks in this list.
|
||||||
|
_anti_gc_callbacks = [] # type: List[Callable[[], None]]
|
||||||
|
|
||||||
## Initializes a new cluster API client.
|
## Initializes a new cluster API client.
|
||||||
# \param address: The network address of the cluster to call.
|
# \param address: The network address of the cluster to call.
|
||||||
# \param on_error: The callback to be called whenever we receive errors from the server.
|
# \param on_error: The callback to be called whenever we receive errors from the server.
|
||||||
|
@ -33,8 +36,6 @@ class ClusterApiClient:
|
||||||
self._manager = QNetworkAccessManager()
|
self._manager = QNetworkAccessManager()
|
||||||
self._address = address
|
self._address = address
|
||||||
self._on_error = on_error
|
self._on_error = on_error
|
||||||
# In order to avoid garbage collection we keep the callbacks in this list.
|
|
||||||
self._anti_gc_callbacks = [] # type: List[Callable[[], None]]
|
|
||||||
|
|
||||||
## Get printer system information.
|
## Get printer system information.
|
||||||
# \param on_finished: The callback in case the response is successful.
|
# \param on_finished: The callback in case the response is successful.
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2019 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 typing import Dict, Optional, Callable
|
from typing import Dict, Optional, Callable, List
|
||||||
|
|
||||||
from UM import i18nCatalog
|
from UM import i18nCatalog
|
||||||
|
from UM.Logger import Logger
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from UM.Version import Version
|
from UM.Version import Version
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice
|
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
|
|
||||||
from .ZeroConfClient import ZeroConfClient
|
from .ZeroConfClient import ZeroConfClient
|
||||||
from .ClusterApiClient import ClusterApiClient
|
from .ClusterApiClient import ClusterApiClient
|
||||||
from .LocalClusterOutputDevice import LocalClusterOutputDevice
|
from .LocalClusterOutputDevice import LocalClusterOutputDevice
|
||||||
|
from ..UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
|
||||||
from ..CloudFlowMessage import CloudFlowMessage
|
from ..CloudFlowMessage import CloudFlowMessage
|
||||||
|
from ..Messages.LegacyDeviceNoLongerSupportedMessage import LegacyDeviceNoLongerSupportedMessage
|
||||||
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
|
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,15 +47,10 @@ class LocalClusterOutputDeviceManager:
|
||||||
self._zero_conf_client.addedNetworkCluster.connect(self._onDeviceDiscovered)
|
self._zero_conf_client.addedNetworkCluster.connect(self._onDeviceDiscovered)
|
||||||
self._zero_conf_client.removedNetworkCluster.connect(self._onDiscoveredDeviceRemoved)
|
self._zero_conf_client.removedNetworkCluster.connect(self._onDiscoveredDeviceRemoved)
|
||||||
|
|
||||||
# Persistent dict containing manually connected clusters.
|
|
||||||
self._manual_instances = {} # type: Dict[str, Optional[Callable]]
|
|
||||||
|
|
||||||
## Start the network discovery.
|
## Start the network discovery.
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
self._zero_conf_client.start()
|
self._zero_conf_client.start()
|
||||||
# Load all manual devices.
|
for address in self._getStoredManualAddresses():
|
||||||
self._manual_instances = self._getStoredManualInstances()
|
|
||||||
for address in self._manual_instances:
|
|
||||||
self.addManualDevice(address)
|
self.addManualDevice(address)
|
||||||
|
|
||||||
## Stop network discovery and clean up discovered devices.
|
## Stop network discovery and clean up discovered devices.
|
||||||
|
@ -65,11 +62,8 @@ class LocalClusterOutputDeviceManager:
|
||||||
|
|
||||||
## Add a networked printer manually by address.
|
## Add a networked printer manually by address.
|
||||||
def addManualDevice(self, address: str, callback: Optional[Callable[[bool, str], None]] = None) -> None:
|
def addManualDevice(self, address: str, callback: Optional[Callable[[bool, str], None]] = None) -> None:
|
||||||
self._manual_instances[address] = callback
|
|
||||||
new_manual_devices = ",".join(self._manual_instances.keys())
|
|
||||||
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_manual_devices)
|
|
||||||
api_client = ClusterApiClient(address, lambda error: print(error))
|
api_client = ClusterApiClient(address, lambda error: print(error))
|
||||||
api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status))
|
api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status, callback))
|
||||||
|
|
||||||
## Remove a manually added networked printer.
|
## Remove a manually added networked printer.
|
||||||
def removeManualDevice(self, device_id: str, address: Optional[str] = None) -> None:
|
def removeManualDevice(self, device_id: str, address: Optional[str] = None) -> None:
|
||||||
|
@ -80,19 +74,15 @@ class LocalClusterOutputDeviceManager:
|
||||||
address = address or self._discovered_devices[device_id].ipAddress
|
address = address or self._discovered_devices[device_id].ipAddress
|
||||||
self._onDiscoveredDeviceRemoved(device_id)
|
self._onDiscoveredDeviceRemoved(device_id)
|
||||||
|
|
||||||
if address in self._manual_instances:
|
if address in self._getStoredManualAddresses():
|
||||||
manual_instance_callback = self._manual_instances.pop(address)
|
self._removeStoredManualAddress(address)
|
||||||
new_devices = ",".join(self._manual_instances.keys())
|
|
||||||
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_devices)
|
|
||||||
if manual_instance_callback:
|
|
||||||
CuraApplication.getInstance().callLater(manual_instance_callback, False, address)
|
|
||||||
|
|
||||||
## Force reset all network device connections.
|
## Force reset all network device connections.
|
||||||
def refreshConnections(self):
|
def refreshConnections(self) -> None:
|
||||||
self._connectToActiveMachine()
|
self._connectToActiveMachine()
|
||||||
|
|
||||||
## Callback for when the active machine was changed by the user or a new remote cluster was found.
|
## Callback for when the active machine was changed by the user or a new remote cluster was found.
|
||||||
def _connectToActiveMachine(self):
|
def _connectToActiveMachine(self) -> None:
|
||||||
active_machine = CuraApplication.getInstance().getGlobalContainerStack()
|
active_machine = CuraApplication.getInstance().getGlobalContainerStack()
|
||||||
if not active_machine:
|
if not active_machine:
|
||||||
return
|
return
|
||||||
|
@ -108,10 +98,8 @@ class LocalClusterOutputDeviceManager:
|
||||||
CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device.key)
|
CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device.key)
|
||||||
|
|
||||||
## Callback for when a manual device check request was responded to.
|
## Callback for when a manual device check request was responded to.
|
||||||
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None:
|
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus,
|
||||||
callback = self._manual_instances.get(address, None)
|
callback: Optional[Callable[[bool, str], None]] = None) -> None:
|
||||||
if callback is None:
|
|
||||||
return
|
|
||||||
self._onDeviceDiscovered("manual:{}".format(address), address, {
|
self._onDeviceDiscovered("manual:{}".format(address), address, {
|
||||||
b"name": status.name.encode("utf-8"),
|
b"name": status.name.encode("utf-8"),
|
||||||
b"address": address.encode("utf-8"),
|
b"address": address.encode("utf-8"),
|
||||||
|
@ -120,6 +108,8 @@ class LocalClusterOutputDeviceManager:
|
||||||
b"firmware_version": status.firmware.encode("utf-8"),
|
b"firmware_version": status.firmware.encode("utf-8"),
|
||||||
b"cluster_size": b"1"
|
b"cluster_size": b"1"
|
||||||
})
|
})
|
||||||
|
self._storeManualAddress(address)
|
||||||
|
if callback is not None:
|
||||||
CuraApplication.getInstance().callLater(callback, True, address)
|
CuraApplication.getInstance().callLater(callback, True, address)
|
||||||
|
|
||||||
## Returns a dict of printer BOM numbers to machine types.
|
## Returns a dict of printer BOM numbers to machine types.
|
||||||
|
@ -139,6 +129,7 @@ class LocalClusterOutputDeviceManager:
|
||||||
## Add a new device.
|
## Add a new device.
|
||||||
def _onDeviceDiscovered(self, key: str, address: str, properties: Dict[bytes, bytes]) -> None:
|
def _onDeviceDiscovered(self, key: str, address: str, properties: Dict[bytes, bytes]) -> None:
|
||||||
cluster_size = int(properties.get(b"cluster_size", -1))
|
cluster_size = int(properties.get(b"cluster_size", -1))
|
||||||
|
firmware_version = Version(properties.get(b"firmware", "1.0.0"))
|
||||||
machine_identifier = properties.get(b"machine", b"").decode("utf-8")
|
machine_identifier = properties.get(b"machine", b"").decode("utf-8")
|
||||||
printer_type_identifiers = self._getPrinterTypeIdentifiers()
|
printer_type_identifiers = self._getPrinterTypeIdentifiers()
|
||||||
|
|
||||||
|
@ -149,8 +140,8 @@ class LocalClusterOutputDeviceManager:
|
||||||
properties[b"printer_type"] = bytes(p_type, encoding="utf8")
|
properties[b"printer_type"] = bytes(p_type, encoding="utf8")
|
||||||
break
|
break
|
||||||
|
|
||||||
# We no longer support legacy devices, so check that here.
|
# We no longer support legacy devices, prevent them from showing up in the discovered devices list.
|
||||||
if cluster_size == -1:
|
if cluster_size == -1 or firmware_version < self.MIN_SUPPORTED_CLUSTER_VERSION:
|
||||||
return
|
return
|
||||||
|
|
||||||
device = LocalClusterOutputDevice(key, address, properties)
|
device = LocalClusterOutputDevice(key, address, properties)
|
||||||
|
@ -191,16 +182,40 @@ class LocalClusterOutputDeviceManager:
|
||||||
self._connectToOutputDevice(device, active_machine)
|
self._connectToOutputDevice(device, active_machine)
|
||||||
CloudFlowMessage(device.ipAddress).show() # Nudge the user to start using Ultimaker Cloud.
|
CloudFlowMessage(device.ipAddress).show() # Nudge the user to start using Ultimaker Cloud.
|
||||||
|
|
||||||
|
## Add an address to the stored preferences.
|
||||||
|
def _storeManualAddress(self, address: str) -> None:
|
||||||
|
stored_addresses = self._getStoredManualAddresses()
|
||||||
|
if address in stored_addresses:
|
||||||
|
return # Prevent duplicates.
|
||||||
|
stored_addresses.append(address)
|
||||||
|
new_value = ",".join(stored_addresses)
|
||||||
|
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_value)
|
||||||
|
|
||||||
|
## Remove an address from the stored preferences.
|
||||||
|
def _removeStoredManualAddress(self, address: str) -> None:
|
||||||
|
stored_addresses = self._getStoredManualAddresses()
|
||||||
|
try:
|
||||||
|
stored_addresses.remove(address) # Can throw a ValueError
|
||||||
|
new_value = ",".join(stored_addresses)
|
||||||
|
CuraApplication.getInstance().getPreferences().setValue(self.MANUAL_DEVICES_PREFERENCE_KEY, new_value)
|
||||||
|
except ValueError:
|
||||||
|
Logger.log("w", "Could not remove address from stored_addresses, it was not there")
|
||||||
|
|
||||||
## Load the user-configured manual devices from Cura preferences.
|
## Load the user-configured manual devices from Cura preferences.
|
||||||
def _getStoredManualInstances(self) -> Dict[str, Optional[Callable]]:
|
def _getStoredManualAddresses(self) -> List[str]:
|
||||||
preferences = CuraApplication.getInstance().getPreferences()
|
preferences = CuraApplication.getInstance().getPreferences()
|
||||||
preferences.addPreference(self.MANUAL_DEVICES_PREFERENCE_KEY, "")
|
preferences.addPreference(self.MANUAL_DEVICES_PREFERENCE_KEY, "")
|
||||||
manual_instances = preferences.getValue(self.MANUAL_DEVICES_PREFERENCE_KEY).split(",")
|
manual_instances = preferences.getValue(self.MANUAL_DEVICES_PREFERENCE_KEY).split(",")
|
||||||
return {address: None for address in manual_instances}
|
return manual_instances
|
||||||
|
|
||||||
## Add a device to the current active machine.
|
## Add a device to the current active machine.
|
||||||
@staticmethod
|
def _connectToOutputDevice(self, device: UltimakerNetworkedPrinterOutputDevice, machine: GlobalStack) -> None:
|
||||||
def _connectToOutputDevice(device: PrinterOutputDevice, active_machine: GlobalStack) -> None:
|
|
||||||
|
# Make sure users know that we no longer support legacy devices.
|
||||||
|
if device.clusterSize < 1 or Version(device.firmwareVersion) < self.MIN_SUPPORTED_CLUSTER_VERSION:
|
||||||
|
LegacyDeviceNoLongerSupportedMessage().show()
|
||||||
|
return
|
||||||
|
|
||||||
device.connect()
|
device.connect()
|
||||||
active_machine.addConfiguredConnectionType(device.connectionType.value)
|
machine.addConfiguredConnectionType(device.connectionType.value)
|
||||||
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)
|
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue