Add firmware check

Contributes to CL-1222
This commit is contained in:
Ian Paschal 2019-02-04 16:02:38 +01:00
parent 2a3a1d6e35
commit f2ddb2808f
3 changed files with 59 additions and 46 deletions

View file

@ -517,6 +517,12 @@ class MachineManager(QObject):
return self._global_container_stack.getId() return self._global_container_stack.getId()
return "" return ""
@pyqtProperty(str, notify = globalContainerChanged)
def activeMachineFirmwareVersion(self) -> str:
if not self._printer_output_devices[0]:
return ""
return self._printer_output_devices[0].firmwareVersion
@pyqtProperty(bool, notify = printerConnectedStatusChanged) @pyqtProperty(bool, notify = printerConnectedStatusChanged)
def printerConnected(self) -> bool: def printerConnected(self) -> bool:
return bool(self._printer_output_devices) return bool(self._printer_output_devices)

View file

@ -45,7 +45,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
activePrinterChanged = pyqtSignal() activePrinterChanged = pyqtSignal()
activeCameraUrlChanged = pyqtSignal() activeCameraUrlChanged = pyqtSignal()
receivedPrintJobsChanged = pyqtSignal() receivedPrintJobsChanged = pyqtSignal()
cloudFlowIsPossible = pyqtSignal()
# Notify can only use signals that are defined by the class that they are in, not inherited ones. # Notify can only use signals that are defined by the class that they are in, not inherited ones.
# Therefore we create a private signal used to trigger the printersChanged signal. # Therefore we create a private signal used to trigger the printersChanged signal.
@ -68,18 +67,9 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/MonitorStage.qml") self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../resources/qml/MonitorStage.qml")
self._account = self._application.getCuraAPI().account
# Trigger the printersChanged signal when the private signal is triggered # Trigger the printersChanged signal when the private signal is triggered
self.printersChanged.connect(self._clusterPrintersChanged) self.printersChanged.connect(self._clusterPrintersChanged)
# Check if cloud flow is possible when user logs in
self._account.loginStateChanged.connect(self.checkCloudFlowIsPossible)
# Listen for when Cloud Flow is possible
self.cloudFlowIsPossible.connect(self._onCloudFlowPossible)
self._accepts_commands = True # type: bool self._accepts_commands = True # type: bool
# Cluster does not have authentication, so default to authenticated # Cluster does not have authentication, so default to authenticated
@ -677,40 +667,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
job = SendMaterialJob(device = self) job = SendMaterialJob(device = self)
job.run() job.run()
## Check if the prerequsites are in place to start the cloud flow
def checkCloudFlowIsPossible(self):
Logger.log("d", "Checking if cloud connection is possible...")
# Check #1: User is logged in with an Ultimaker account
if not self._account.isLoggedIn:
Logger.log("d", "Cloud Flow not possible: User not logged in!")
return
# Check #2: Machine has a network connection
if not self._application.getMachineManager().activeMachineHasActiveNetworkConnection:
Logger.log("d", "Cloud Flow not possible: Machine is not connected!")
# TODO: This should only be network connections, not cloud connections
return
# Check #3: Machine has correct firmware version
# Logger.log("d", "Cloud Flow not possible: Machine does not have necessary firmware!")
# return
# TODO: Check if machine is already set up to be cloud
self.cloudFlowIsPossible.emit()
Logger.log("d", "Cloud flow is ready to go!")
def _onCloudFlowPossible(self):
# Cloud flow is possible, so show the message
self._start_cloud_flow_message = Message(i18n_catalog.i18nc("@info:status", "Chain so thin when a breeze roll by, man it flow... man it flow..."))
self._start_cloud_flow_message.show()
return
def loadJsonFromReply(reply: QNetworkReply) -> Optional[List[Dict[str, Any]]]: def loadJsonFromReply(reply: QNetworkReply) -> Optional[List[Dict[str, Any]]]:
try: try:
result = json.loads(bytes(reply.readAll()).decode("utf-8")) result = json.loads(bytes(reply.readAll()).decode("utf-8"))

View file

@ -7,17 +7,20 @@ from time import time
from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo from zeroconf import Zeroconf, ServiceBrowser, ServiceStateChange, ServiceInfo
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
from PyQt5.QtCore import QUrl from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
from UM.Logger import Logger from UM.Logger import Logger
from UM.Signal import Signal, signalemitter from UM.Signal import Signal, signalemitter
from UM.Version import Version from UM.Version import Version
from UM.Message import Message
from UM.i18n import i18nCatalog
from . import ClusterUM3OutputDevice, LegacyUM3OutputDevice from . import ClusterUM3OutputDevice, LegacyUM3OutputDevice
from .Cloud.CloudOutputDeviceManager import CloudOutputDeviceManager from .Cloud.CloudOutputDeviceManager import CloudOutputDeviceManager
i18n_catalog = i18nCatalog("cura")
## This plugin handles the connection detection & creation of output device objects for the UM3 printer. ## This plugin handles the connection detection & creation of output device objects for the UM3 printer.
# Zero-Conf is used to detect printers, which are saved in a dict. # Zero-Conf is used to detect printers, which are saved in a dict.
@ -27,6 +30,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
addDeviceSignal = Signal() addDeviceSignal = Signal()
removeDeviceSignal = Signal() removeDeviceSignal = Signal()
discoveredDevicesChanged = Signal() discoveredDevicesChanged = Signal()
cloudFlowIsPossible = Signal()
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -34,6 +38,8 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._zero_conf = None self._zero_conf = None
self._zero_conf_browser = None self._zero_conf_browser = None
self._application = CuraApplication.getInstance()
# Create a cloud output device manager that abstracts all cloud connection logic away. # Create a cloud output device manager that abstracts all cloud connection logic away.
self._cloud_output_device_manager = CloudOutputDeviceManager() self._cloud_output_device_manager = CloudOutputDeviceManager()
@ -41,7 +47,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self.addDeviceSignal.connect(self._onAddDevice) self.addDeviceSignal.connect(self._onAddDevice)
self.removeDeviceSignal.connect(self._onRemoveDevice) self.removeDeviceSignal.connect(self._onRemoveDevice)
CuraApplication.getInstance().globalContainerStackChanged.connect(self.reCheckConnections) self._application.globalContainerStackChanged.connect(self.reCheckConnections)
self._discovered_devices = {} self._discovered_devices = {}
@ -49,6 +55,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._network_manager.finished.connect(self._onNetworkRequestFinished) self._network_manager.finished.connect(self._onNetworkRequestFinished)
self._min_cluster_version = Version("4.0.0") self._min_cluster_version = Version("4.0.0")
self._min_cloud_version = Version("5.1.5")
self._api_version = "1" self._api_version = "1"
self._api_prefix = "/api/v" + self._api_version + "/" self._api_prefix = "/api/v" + self._api_version + "/"
@ -74,6 +81,14 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self._service_changed_request_thread = Thread(target=self._handleOnServiceChangedRequests, daemon=True) self._service_changed_request_thread = Thread(target=self._handleOnServiceChangedRequests, daemon=True)
self._service_changed_request_thread.start() self._service_changed_request_thread.start()
self._account = self._application.getCuraAPI().account
# Check if cloud flow is possible when user logs in
self._account.loginStateChanged.connect(self.checkCloudFlowIsPossible)
# Listen for when Cloud Flow is possible
self.cloudFlowIsPossible.connect(self._onCloudFlowPossible)
def getDiscoveredDevices(self): def getDiscoveredDevices(self):
return self._discovered_devices return self._discovered_devices
@ -292,6 +307,7 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"): if global_container_stack and device.getId() == global_container_stack.getMetaDataEntry("um_network_key"):
# Ensure that the configured connection type is set. # Ensure that the configured connection type is set.
global_container_stack.addConfiguredConnectionType(device.connectionType.value) global_container_stack.addConfiguredConnectionType(device.connectionType.value)
# global_container_stack.setFirmwareVersion(device.firmwareVersion)
device.connect() device.connect()
device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged) device.connectionStateChanged.connect(self._onDeviceConnectionStateChanged)
@ -370,3 +386,38 @@ class UM3OutputDevicePlugin(OutputDevicePlugin):
self.removeDeviceSignal.emit(str(name)) self.removeDeviceSignal.emit(str(name))
return True return True
## Check if the prerequsites are in place to start the cloud flow
def checkCloudFlowIsPossible(self):
Logger.log("d", "Checking if cloud connection is possible...")
# TODO: Skip if already using cloud connection
# Check #1: User is logged in with an Ultimaker account
if not self._account.isLoggedIn:
Logger.log("d", "Cloud Flow not possible: User not logged in!")
return
# Check #2: Machine has a network connection
if not self._application.getMachineManager().activeMachineHasActiveNetworkConnection:
Logger.log("d", "Cloud Flow not possible: Machine is not connected!")
# TODO: This should only be network connections, not cloud connections
return
# Check #3: Machine has correct firmware version
firmware_version = self._application.getMachineManager().activeMachineFirmwareVersion
if not Version(firmware_version) > self._min_cloud_version:
Logger.log("d",
"Cloud Flow not possible: Machine firmware (%s) is too low! (Requires version %s)",
firmware_version,
self._min_cloud_version)
return
self.cloudFlowIsPossible.emit()
Logger.log("d", "Cloud flow is ready to go!")
def _onCloudFlowPossible(self):
# Cloud flow is possible, so show the message
self._start_cloud_flow_message = Message(i18n_catalog.i18nc("@info:status", "Chain so thin when a breeze roll by, man it flow... man it flow..."))
self._start_cloud_flow_message.show()
return