Fix adding by manual IP, code improvements

This commit is contained in:
ChrisTerBeke 2019-08-07 00:38:07 +02:00
parent ac177659e5
commit 8a2e394abc
No known key found for this signature in database
GPG key ID: A49F1AB9D7E0C263
4 changed files with 73 additions and 36 deletions

View file

@ -35,6 +35,9 @@ class CloudApiClient:
CLUSTER_API_ROOT = "{}/connect/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.
# \param account: The user's account object
# \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._on_error = on_error
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.
@property

View file

@ -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
)

View file

@ -25,6 +25,9 @@ class ClusterApiClient:
PRINTER_API_PREFIX = "/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.
# \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.
@ -33,8 +36,6 @@ class ClusterApiClient:
self._manager = QNetworkAccessManager()
self._address = address
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.
# \param on_finished: The callback in case the response is successful.

View file

@ -1,19 +1,21 @@
# Copyright (c) 2019 Ultimaker B.V.
# 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.Logger import Logger
from UM.Signal import Signal
from UM.Version import Version
from cura.CuraApplication import CuraApplication
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice
from cura.Settings.GlobalStack import GlobalStack
from .ZeroConfClient import ZeroConfClient
from .ClusterApiClient import ClusterApiClient
from .LocalClusterOutputDevice import LocalClusterOutputDevice
from ..UltimakerNetworkedPrinterOutputDevice import UltimakerNetworkedPrinterOutputDevice
from ..CloudFlowMessage import CloudFlowMessage
from ..Messages.LegacyDeviceNoLongerSupportedMessage import LegacyDeviceNoLongerSupportedMessage
from ..Models.Http.PrinterSystemStatus import PrinterSystemStatus
@ -45,15 +47,10 @@ class LocalClusterOutputDeviceManager:
self._zero_conf_client.addedNetworkCluster.connect(self._onDeviceDiscovered)
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.
def start(self) -> None:
self._zero_conf_client.start()
# Load all manual devices.
self._manual_instances = self._getStoredManualInstances()
for address in self._manual_instances:
for address in self._getStoredManualAddresses():
self.addManualDevice(address)
## Stop network discovery and clean up discovered devices.
@ -65,11 +62,8 @@ class LocalClusterOutputDeviceManager:
## Add a networked printer manually by address.
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.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status))
api_client.getSystem(lambda status: self._onCheckManualDeviceResponse(address, status, callback))
## Remove a manually added networked printer.
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
self._onDiscoveredDeviceRemoved(device_id)
if address in self._manual_instances:
manual_instance_callback = self._manual_instances.pop(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)
if address in self._getStoredManualAddresses():
self._removeStoredManualAddress(address)
## Force reset all network device connections.
def refreshConnections(self):
def refreshConnections(self) -> None:
self._connectToActiveMachine()
## 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()
if not active_machine:
return
@ -108,10 +98,8 @@ class LocalClusterOutputDeviceManager:
CuraApplication.getInstance().getOutputDeviceManager().removeOutputDevice(device.key)
## Callback for when a manual device check request was responded to.
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus) -> None:
callback = self._manual_instances.get(address, None)
if callback is None:
return
def _onCheckManualDeviceResponse(self, address: str, status: PrinterSystemStatus,
callback: Optional[Callable[[bool, str], None]] = None) -> None:
self._onDeviceDiscovered("manual:{}".format(address), address, {
b"name": status.name.encode("utf-8"),
b"address": address.encode("utf-8"),
@ -120,6 +108,8 @@ class LocalClusterOutputDeviceManager:
b"firmware_version": status.firmware.encode("utf-8"),
b"cluster_size": b"1"
})
self._storeManualAddress(address)
if callback is not None:
CuraApplication.getInstance().callLater(callback, True, address)
## Returns a dict of printer BOM numbers to machine types.
@ -139,6 +129,7 @@ class LocalClusterOutputDeviceManager:
## Add a new device.
def _onDeviceDiscovered(self, key: str, address: str, properties: Dict[bytes, bytes]) -> None:
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")
printer_type_identifiers = self._getPrinterTypeIdentifiers()
@ -149,8 +140,8 @@ class LocalClusterOutputDeviceManager:
properties[b"printer_type"] = bytes(p_type, encoding="utf8")
break
# We no longer support legacy devices, so check that here.
if cluster_size == -1:
# We no longer support legacy devices, prevent them from showing up in the discovered devices list.
if cluster_size == -1 or firmware_version < self.MIN_SUPPORTED_CLUSTER_VERSION:
return
device = LocalClusterOutputDevice(key, address, properties)
@ -191,16 +182,40 @@ class LocalClusterOutputDeviceManager:
self._connectToOutputDevice(device, active_machine)
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.
def _getStoredManualInstances(self) -> Dict[str, Optional[Callable]]:
def _getStoredManualAddresses(self) -> List[str]:
preferences = CuraApplication.getInstance().getPreferences()
preferences.addPreference(self.MANUAL_DEVICES_PREFERENCE_KEY, "")
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.
@staticmethod
def _connectToOutputDevice(device: PrinterOutputDevice, active_machine: GlobalStack) -> None:
def _connectToOutputDevice(self, device: UltimakerNetworkedPrinterOutputDevice, 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()
active_machine.addConfiguredConnectionType(device.connectionType.value)
machine.addConfiguredConnectionType(device.connectionType.value)
CuraApplication.getInstance().getOutputDeviceManager().addOutputDevice(device)