From 2e3abbc9044c82e5dc858f52e34d027b0cbee10c Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Sat, 13 Oct 2018 21:55:33 +0200 Subject: [PATCH] Put the firmware-update meta-data in the 'normal' printer definitions and make the code handle that. --- .../FirmwareUpdateChecker.py | 31 +++------- .../FirmwareUpdateCheckerJob.py | 30 ++++++---- .../FirmwareUpdateCheckerLookup.py | 57 ++++++------------- .../FirmwareUpdateCheckerMessage.py | 6 +- .../resources/machines.json | 33 ----------- resources/definitions/ultimaker3.def.json | 11 +++- .../definitions/ultimaker3_extended.def.json | 11 +++- resources/definitions/ultimaker_s5.def.json | 7 ++- 8 files changed, 73 insertions(+), 113 deletions(-) delete mode 100644 plugins/FirmwareUpdateChecker/resources/machines.json diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateChecker.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateChecker.py index 8c0ea1bea2..415931b7ec 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateChecker.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateChecker.py @@ -10,15 +10,12 @@ from typing import Set from UM.Extension import Extension from UM.Application import Application from UM.Logger import Logger -from UM.PluginRegistry import PluginRegistry -from UM.Qt.QtApplication import QtApplication from UM.i18n import i18nCatalog from UM.Settings.ContainerRegistry import ContainerRegistry from cura.Settings.GlobalStack import GlobalStack from .FirmwareUpdateCheckerJob import FirmwareUpdateCheckerJob -from .FirmwareUpdateCheckerLookup import FirmwareUpdateCheckerLookup, getSettingsKeyForMachine from .FirmwareUpdateCheckerMessage import FirmwareUpdateCheckerMessage i18n_catalog = i18nCatalog("cura") @@ -38,18 +35,14 @@ class FirmwareUpdateChecker(Extension): if Application.getInstance().getPreferences().getValue("info/automatic_update_check"): ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) - # Partly initialize after creation, since we need our own path from the plugin-manager. - self._download_url = None self._check_job = None self._checked_printer_names = set() # type: Set[str] - self._lookups = None - QtApplication.pluginsLoaded.connect(self._onPluginsLoaded) ## Callback for the message that is spawned when there is a new version. def _onActionTriggered(self, message, action): if action == FirmwareUpdateCheckerMessage.STR_ACTION_DOWNLOAD: machine_id = message.getMachineId() - download_url = self._lookups.getRedirectUserFor(machine_id) + download_url = message.getDownloadUrl() if download_url is not None: if QDesktopServices.openUrl(QUrl(download_url)): Logger.log("i", "Redirected browser to {0} to show newly available firmware.".format(download_url)) @@ -66,18 +59,6 @@ class FirmwareUpdateChecker(Extension): def _onJobFinished(self, *args, **kwargs): self._check_job = None - def _onPluginsLoaded(self): - if self._lookups is not None: - return - - self._lookups = FirmwareUpdateCheckerLookup(os.path.join(PluginRegistry.getInstance().getPluginPath( - "FirmwareUpdateChecker"), "resources/machines.json")) - - # Initialize the Preference called `latest_checked_firmware` that stores the last version - # checked for each printer. - for machine_id in self._lookups.getMachineIds(): - Application.getInstance().getPreferences().addPreference(getSettingsKeyForMachine(machine_id), "") - ## Connect with software.ultimaker.com, load latest.version and check version info. # If the version info is different from the current version, spawn a message to # allow the user to download it. @@ -85,16 +66,18 @@ class FirmwareUpdateChecker(Extension): # \param silent type(boolean) Suppresses messages other than "new version found" messages. # This is used when checking for a new firmware version at startup. def checkFirmwareVersion(self, container = None, silent = False): - if self._lookups is None: - self._onPluginsLoaded() - container_name = container.definition.getName() if container_name in self._checked_printer_names: return self._checked_printer_names.add(container_name) + metadata = container.definition.getMetaData().get("firmware_update_info") + if metadata is None: + Logger.log("i", "No machine with name {0} in list of firmware to check.".format(container_name)) + return + self._check_job = FirmwareUpdateCheckerJob(container = container, silent = silent, - lookups = self._lookups, + machine_name = container_name, metadata = metadata, callback = self._onActionTriggered) self._check_job.start() self._check_job.finished.connect(self._onJobFinished) diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py index f39f4c8cea..2e15208336 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerJob.py @@ -9,7 +9,7 @@ from UM.Version import Version import urllib.request from urllib.error import URLError -from typing import Dict +from typing import Dict, Optional from .FirmwareUpdateCheckerLookup import FirmwareUpdateCheckerLookup, getSettingsKeyForMachine from .FirmwareUpdateCheckerMessage import FirmwareUpdateCheckerMessage @@ -25,13 +25,15 @@ class FirmwareUpdateCheckerJob(Job): ZERO_VERSION = Version(STRING_ZERO_VERSION) EPSILON_VERSION = Version(STRING_EPSILON_VERSION) - def __init__(self, container, silent, lookups: FirmwareUpdateCheckerLookup, callback) -> None: + def __init__(self, container, silent, machine_name, metadata, callback) -> None: super().__init__() self._container = container self.silent = silent self._callback = callback - self._lookups = lookups + self._machine_name = machine_name + self._metadata = metadata + self._lookups = None # type:Optional[FirmwareUpdateCheckerLookup] self._headers = {} # type:Dict[str, str] # Don't set headers yet. def getUrlResponse(self, url: str) -> str: @@ -50,10 +52,12 @@ class FirmwareUpdateCheckerJob(Job): raw_str = response.split("\n", 1)[0].rstrip() return Version(raw_str) - def getCurrentVersionForMachine(self, machine_id: int) -> Version: + def getCurrentVersion(self) -> Version: max_version = self.ZERO_VERSION + if self._lookups is None: + return max_version - machine_urls = self._lookups.getCheckUrlsFor(machine_id) + machine_urls = self._lookups.getCheckUrls() if machine_urls is not None: for url in machine_urls: version = self.parseVersionResponse(self.getUrlResponse(url)) @@ -61,16 +65,20 @@ class FirmwareUpdateCheckerJob(Job): max_version = version if max_version < self.EPSILON_VERSION: - Logger.log("w", "MachineID {0} not handled!".format(repr(machine_id))) + Logger.log("w", "MachineID {0} not handled!".format(self._lookups.getMachineName())) return max_version def run(self): if self._lookups is None: - Logger.log("e", "Can not check for a new release. URL not set!") - return + self._lookups = FirmwareUpdateCheckerLookup(self._machine_name, self._metadata) try: + # Initialize a Preference that stores the last version checked for this printer. + Application.getInstance().getPreferences().addPreference( + getSettingsKeyForMachine(self._lookups.getMachineId()), "") + + # Get headers application_name = Application.getInstance().getApplicationName() application_version = Application.getInstance().getVersion() self._headers = {"User-Agent": "%s - %s" % (application_name, application_version)} @@ -79,11 +87,11 @@ class FirmwareUpdateCheckerJob(Job): machine_name = self._container.definition.getName() # If it is not None, then we compare between the checked_version and the current_version - machine_id = self._lookups.getMachineByName(machine_name.lower()) + machine_id = self._lookups.getMachineId() if machine_id is not None: Logger.log("i", "You have a(n) {0} in the printer list. Let's check the firmware!".format(machine_name)) - current_version = self.getCurrentVersionForMachine(machine_id) + current_version = self.getCurrentVersion() # If it is the first time the version is checked, the checked_version is "" setting_key_str = getSettingsKeyForMachine(machine_id) @@ -99,7 +107,7 @@ class FirmwareUpdateCheckerJob(Job): # notify the user when no new firmware version is available. if (checked_version != "") and (checked_version != current_version): Logger.log("i", "SHOWING FIRMWARE UPDATE MESSAGE") - message = FirmwareUpdateCheckerMessage(machine_id, machine_name) + message = FirmwareUpdateCheckerMessage(machine_id, machine_name, self._lookups.getRedirectUserUrl()) message.actionTriggered.connect(self._callback) message.show() else: diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerLookup.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerLookup.py index ff4e9ce73d..a21ad3f0e5 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerLookup.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerLookup.py @@ -1,11 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -import json - -from typing import Callable, Dict, List, Optional - -from UM.Logger import Logger +from typing import List, Optional from UM.i18n import i18nCatalog i18n_catalog = i18nCatalog("cura") @@ -17,44 +13,23 @@ def getSettingsKeyForMachine(machine_id: int) -> str: class FirmwareUpdateCheckerLookup: - def __init__(self, json_path) -> None: - # Open the .json file with the needed lookup-lists for each machine(/model) and retrieve "raw" json. - with open(json_path, "r", encoding = "utf-8") as json_file: - machines_json = json.load(json_file).get("machines") - if machines_json is None: - Logger.log("e", "Missing or inaccessible: {0}".format(json_path)) - return - + def __init__(self, machine_name, machine_json) -> None: # Parse all the needed lookup-tables from the ".json" file(s) in the resources folder. - self._machine_ids = [] # type:List[int] - self._machine_per_name = {} # type:Dict[str, int] - self._parse_version_url_per_machine = {} # type:Dict[int, Callable] - self._check_urls_per_machine = {} # type:Dict[int, List[str]] - self._redirect_user_per_machine = {} # type:Dict[int, str] - try: - for machine_json in machines_json: - machine_id = machine_json.get("id") - machine_name = machine_json.get("name").lower() # Lower in case upper-case char are added to the json. - self._machine_ids.append(machine_id) - self._machine_per_name[machine_name] = machine_id - self._check_urls_per_machine[machine_id] = [] # Multiple check-urls: see "_comment" in the .json file. - for check_url in machine_json.get("check_urls"): - self._check_urls_per_machine[machine_id].append(check_url) - self._redirect_user_per_machine[machine_id] = machine_json.get("update_url") - except Exception as ex: - Logger.log("e", "Couldn't parse firmware-update-check lookup-lists from file because {0}.".format(ex)) + self._machine_id = machine_json.get("id") + self._machine_name = machine_name.lower() # Lower in-case upper-case chars are added to the original json. + self._check_urls = [] # type:List[str] + for check_url in machine_json.get("check_urls"): + self._check_urls.append(check_url) + self._redirect_user = machine_json.get("update_url") - def getMachineIds(self) -> List[int]: - return self._machine_ids + def getMachineId(self) -> Optional[int]: + return self._machine_id - def getMachineByName(self, machine_name: str) -> Optional[int]: - return self._machine_per_name.get(machine_name) + def getMachineName(self) -> Optional[int]: + return self._machine_name - def getParseVersionUrlFor(self, machine_id: int) -> Optional[Callable]: - return self._parse_version_url_per_machine.get(machine_id) + def getCheckUrls(self) -> Optional[List[str]]: + return self._check_urls - def getCheckUrlsFor(self, machine_id: int) -> Optional[List[str]]: - return self._check_urls_per_machine.get(machine_id) - - def getRedirectUserFor(self, machine_id: int) -> Optional[str]: - return self._redirect_user_per_machine.get(machine_id) + def getRedirectUserUrl(self) -> Optional[str]: + return self._redirect_user diff --git a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerMessage.py b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerMessage.py index 0f13796c29..d509c432b4 100644 --- a/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerMessage.py +++ b/plugins/FirmwareUpdateChecker/FirmwareUpdateCheckerMessage.py @@ -9,7 +9,7 @@ i18n_catalog = i18nCatalog("cura") class FirmwareUpdateCheckerMessage(Message): STR_ACTION_DOWNLOAD = "download" - def __init__(self, machine_id: int, machine_name: str) -> None: + def __init__(self, machine_id: int, machine_name: str, download_url: str) -> None: super().__init__(i18n_catalog.i18nc( "@info Don't translate {machine_name}, since it gets replaced by a printer name!", "New features are available for your {machine_name}! It is recommended to update the firmware on your printer.").format( @@ -19,6 +19,7 @@ class FirmwareUpdateCheckerMessage(Message): "New %s firmware available") % machine_name) self._machine_id = machine_id + self._download_url = download_url self.addAction(self.STR_ACTION_DOWNLOAD, i18n_catalog.i18nc("@action:button", "How to update"), @@ -29,3 +30,6 @@ class FirmwareUpdateCheckerMessage(Message): def getMachineId(self) -> int: return self._machine_id + + def getDownloadUrl(self) -> str: + return self._download_url diff --git a/plugins/FirmwareUpdateChecker/resources/machines.json b/plugins/FirmwareUpdateChecker/resources/machines.json deleted file mode 100644 index d9eaad0abf..0000000000 --- a/plugins/FirmwareUpdateChecker/resources/machines.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "_comment": "There are multiple 'check_urls', because sometimes an URL is about to be phased out, and it's useful to have a new 'future-proof' one at the ready.", - - "machines": - [ - { - "id": 9066, - "name": "ultimaker 3", - "check_urls": - [ - "http://software.ultimaker.com/jedi/releases/latest.version?utm_source=cura&utm_medium=software&utm_campaign=resources", - "http://software.ultimaker.com/releases/firmware/9066/stable/version.txt" - ], - "update_url": "https://ultimaker.com/en/resources/20500-upgrade-firmware" - }, - { - "id": 9511, - "name": "ultimaker 3 extended", - "check_urls": - [ - "http://software.ultimaker.com/jedi/releases/latest.version?utm_source=cura&utm_medium=software&utm_campaign=resources", - "http://software.ultimaker.com/releases/firmware/9511/stable/version.txt" - ], - "update_url": "https://ultimaker.com/en/resources/20500-upgrade-firmware" - }, - { - "id": 9051, - "name": "ultimaker s5", - "check_urls": ["http://software.ultimaker.com/releases/firmware/9051/stable/version.txt"], - "update_url": "https://ultimaker.com/en/resources/20500-upgrade-firmware" - } - ] -} diff --git a/resources/definitions/ultimaker3.def.json b/resources/definitions/ultimaker3.def.json index b1daa6b780..f5e31890f6 100644 --- a/resources/definitions/ultimaker3.def.json +++ b/resources/definitions/ultimaker3.def.json @@ -24,7 +24,16 @@ }, "first_start_actions": [ "DiscoverUM3Action" ], "supported_actions": [ "DiscoverUM3Action" ], - "supports_usb_connection": false + "supports_usb_connection": false, + "firmware_update_info": { + "id": 9066, + "check_urls": + [ + "http://software.ultimaker.com/jedi/releases/latest.version?utm_source=cura&utm_medium=software&utm_campaign=resources", + "http://software.ultimaker.com/releases/firmware/9066/stable/version.txt" + ], + "update_url": "https://ultimaker.com/en/resources/20500-upgrade-firmware" + } }, diff --git a/resources/definitions/ultimaker3_extended.def.json b/resources/definitions/ultimaker3_extended.def.json index eb3cda9320..d13857e428 100644 --- a/resources/definitions/ultimaker3_extended.def.json +++ b/resources/definitions/ultimaker3_extended.def.json @@ -23,7 +23,16 @@ "1": "ultimaker3_extended_extruder_right" }, "first_start_actions": [ "DiscoverUM3Action" ], - "supported_actions": [ "DiscoverUM3Action" ] + "supported_actions": [ "DiscoverUM3Action" ], + "firmware_update_info": { + "id": 9511, + "check_urls": + [ + "http://software.ultimaker.com/jedi/releases/latest.version?utm_source=cura&utm_medium=software&utm_campaign=resources", + "http://software.ultimaker.com/releases/firmware/9511/stable/version.txt" + ], + "update_url": "https://ultimaker.com/en/resources/20500-upgrade-firmware" + } }, "overrides": { diff --git a/resources/definitions/ultimaker_s5.def.json b/resources/definitions/ultimaker_s5.def.json index 2e634787af..6195933869 100644 --- a/resources/definitions/ultimaker_s5.def.json +++ b/resources/definitions/ultimaker_s5.def.json @@ -30,7 +30,12 @@ "first_start_actions": [ "DiscoverUM3Action" ], "supported_actions": [ "DiscoverUM3Action" ], "supports_usb_connection": false, - "weight": -1 + "weight": -1, + "firmware_update_info": { + "id": 9051, + "check_urls": ["http://software.ultimaker.com/releases/firmware/9051/stable/version.txt"], + "update_url": "https://ultimaker.com/en/resources/20500-upgrade-firmware" + } }, "overrides": {