mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 14:37:29 -06:00
Parse the firmware-update-check lookup-tables from a (new) .json instead of hardcoded.
This commit is contained in:
parent
12999f48c8
commit
6c2791f382
3 changed files with 101 additions and 55 deletions
|
@ -1,18 +1,20 @@
|
|||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import json, os
|
||||
from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
|
||||
from UM.Extension import Extension
|
||||
from UM.Application import Application
|
||||
from UM.Logger import Logger
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
from cura.Settings.GlobalStack import GlobalStack
|
||||
|
||||
from .FirmwareUpdateCheckerJob import FirmwareUpdateCheckerJob, MachineId, get_settings_key_for_machine
|
||||
from .FirmwareUpdateCheckerJob import FirmwareUpdateCheckerJob, get_settings_key_for_machine
|
||||
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
|
@ -20,38 +22,23 @@ i18n_catalog = i18nCatalog("cura")
|
|||
# The plugin is currently only usable for applications maintained by Ultimaker. But it should be relatively easy
|
||||
# to change it to work for other applications.
|
||||
class FirmwareUpdateChecker(Extension):
|
||||
JEDI_VERSION_URL = "http://software.ultimaker.com/jedi/releases/latest.version?utm_source=cura&utm_medium=software&utm_campaign=resources"
|
||||
UM_NEW_URL_TEMPLATE = "http://software.ultimaker.com/releases/firmware/{0}/stable/version.txt"
|
||||
VERSION_URLS_PER_MACHINE = \
|
||||
{
|
||||
MachineId.UM3: [JEDI_VERSION_URL, UM_NEW_URL_TEMPLATE.format(MachineId.UM3.value)],
|
||||
MachineId.UM3E: [JEDI_VERSION_URL, UM_NEW_URL_TEMPLATE.format(MachineId.UM3E.value)],
|
||||
MachineId.S5: [UM_NEW_URL_TEMPLATE.format(MachineId.S5.value)]
|
||||
}
|
||||
# The 'new'-style URL is the only way to check for S5 firmware,
|
||||
# and in the future, the UM3 line will also switch over, but for now the old 'JEDI'-style URL is still needed.
|
||||
# TODO: Parse all of that from a file, because this will be a big mess of large static values which gets worse with each printer.
|
||||
# See also the to-do in FirmWareCheckerJob.
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Initialize the Preference called `latest_checked_firmware` that stores the last version
|
||||
# checked for each printer.
|
||||
for machine_id in MachineId:
|
||||
Application.getInstance().getPreferences().addPreference(get_settings_key_for_machine(machine_id), "")
|
||||
|
||||
# Listen to a Signal that indicates a change in the list of printers, just if the user has enabled the
|
||||
# 'check for updates' option
|
||||
Application.getInstance().getPreferences().addPreference("info/automatic_update_check", True)
|
||||
if Application.getInstance().getPreferences().getValue("info/automatic_update_check"):
|
||||
ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded)
|
||||
|
||||
self._late_init = True # Init some things after creation, since we need the path from the plugin-mgr.
|
||||
self._download_url = None
|
||||
self._check_job = None
|
||||
self._name_cache = []
|
||||
|
||||
## Callback for the message that is spawned when there is a new version.
|
||||
# TODO: Set the right download URL for each message!
|
||||
def _onActionTriggered(self, message, action):
|
||||
if action == "download":
|
||||
if self._download_url is not None:
|
||||
|
@ -68,6 +55,25 @@ class FirmwareUpdateChecker(Extension):
|
|||
def _onJobFinished(self, *args, **kwargs):
|
||||
self._check_job = None
|
||||
|
||||
def lateInit(self):
|
||||
self._late_init = False
|
||||
|
||||
# Open the .json file with the needed lookup-lists for each machine(/model) and retrieve 'raw' json.
|
||||
self._machines_json = None
|
||||
json_path = os.path.join(PluginRegistry.getInstance().getPluginPath("FirmwareUpdateChecker"),
|
||||
"resources/machines.json")
|
||||
with open(json_path, "r", encoding="utf-8") as json_file:
|
||||
self._machines_json = json.load(json_file).get("machines")
|
||||
if self._machines_json is None:
|
||||
Logger.log('e', "Missing or inaccessible: {0}".format(json_path))
|
||||
return
|
||||
|
||||
# Initialize the Preference called `latest_checked_firmware` that stores the last version
|
||||
# checked for each printer.
|
||||
for machine_json in self._machines_json:
|
||||
machine_id = machine_json.get("id")
|
||||
Application.getInstance().getPreferences().addPreference(get_settings_key_for_machine(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.
|
||||
|
@ -75,13 +81,16 @@ 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._late_init:
|
||||
self.lateInit()
|
||||
|
||||
container_name = container.definition.getName()
|
||||
if container_name in self._name_cache:
|
||||
return
|
||||
self._name_cache.append(container_name)
|
||||
|
||||
self._check_job = FirmwareUpdateCheckerJob(container = container, silent = silent,
|
||||
urls = self.VERSION_URLS_PER_MACHINE,
|
||||
machines_json = self._machines_json,
|
||||
callback = self._onActionTriggered,
|
||||
set_download_url_callback = self._onSetDownloadUrl)
|
||||
self._check_job.start()
|
||||
|
|
|
@ -16,16 +16,9 @@ import codecs
|
|||
from UM.i18n import i18nCatalog
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
# For UM-machines, these need to match the unique firmware-ID (also used in the URLs), i.o.t. only define in one place.
|
||||
@unique
|
||||
class MachineId(Enum):
|
||||
UM3 = 9066
|
||||
UM3E = 9511
|
||||
S5 = 9051
|
||||
|
||||
|
||||
def get_settings_key_for_machine(machine_id: MachineId) -> str:
|
||||
return "info/latest_checked_firmware_for_{0}".format(machine_id.value)
|
||||
def get_settings_key_for_machine(machine_id: int) -> str:
|
||||
return "info/latest_checked_firmware_for_{0}".format(machine_id)
|
||||
|
||||
|
||||
def default_parse_version_response(response: str) -> Version:
|
||||
|
@ -39,31 +32,39 @@ class FirmwareUpdateCheckerJob(Job):
|
|||
STRING_EPSILON_VERSION = "0.0.1"
|
||||
ZERO_VERSION = Version(STRING_ZERO_VERSION)
|
||||
EPSILON_VERSION = Version(STRING_EPSILON_VERSION)
|
||||
MACHINE_PER_NAME = \
|
||||
{
|
||||
"ultimaker 3": MachineId.UM3,
|
||||
"ultimaker 3 extended": MachineId.UM3E,
|
||||
"ultimaker s5": MachineId.S5
|
||||
}
|
||||
PARSE_VERSION_URL_PER_MACHINE = \
|
||||
{
|
||||
MachineId.UM3: default_parse_version_response,
|
||||
MachineId.UM3E: default_parse_version_response,
|
||||
MachineId.S5: default_parse_version_response
|
||||
}
|
||||
REDIRECT_USER_PER_MACHINE = \
|
||||
{
|
||||
MachineId.UM3: "https://ultimaker.com/en/resources/20500-upgrade-firmware",
|
||||
MachineId.UM3E: "https://ultimaker.com/en/resources/20500-upgrade-firmware",
|
||||
MachineId.S5: "https://ultimaker.com/en/resources/20500-upgrade-firmware"
|
||||
}
|
||||
# TODO: Parse all of that from a file, because this will be a big mess of large static values which gets worse with each printer.
|
||||
JSON_NAME_TO_VERSION_PARSE_FUNCTION = {"default": default_parse_version_response}
|
||||
|
||||
def __init__(self, container=None, silent=False, urls=None, callback=None, set_download_url_callback=None):
|
||||
def __init__(self, container=None, silent=False, machines_json=None, callback=None, set_download_url_callback=None):
|
||||
super().__init__()
|
||||
self._container = container
|
||||
self.silent = silent
|
||||
self._urls = urls
|
||||
|
||||
# Parse all the needed lookup-tables from the '.json' file(s) in the resources folder.
|
||||
# TODO: This should not be here when the merge to master is done, as it will be repeatedly recreated.
|
||||
# It should be a separate object this constructor receives instead.
|
||||
self._machine_ids = []
|
||||
self._machine_per_name = {}
|
||||
self._parse_version_url_per_machine = {}
|
||||
self._check_urls_per_machine = {}
|
||||
self._redirect_user_per_machine = {}
|
||||
try:
|
||||
for machine_json in machines_json:
|
||||
machine_id = machine_json.get("id")
|
||||
machine_name = machine_json.get("name")
|
||||
self._machine_ids.append(machine_id)
|
||||
self._machine_per_name[machine_name] = machine_id
|
||||
version_parse_function = self.JSON_NAME_TO_VERSION_PARSE_FUNCTION.get(machine_json.get("version_parser"))
|
||||
if version_parse_function is None:
|
||||
Logger.log('w', "No version-parse-function specified for machine {0}.".format(machine_name))
|
||||
version_parse_function = default_parse_version_response # Use default instead if nothing is found.
|
||||
self._parse_version_url_per_machine[machine_id] = version_parse_function
|
||||
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:
|
||||
Logger.log('e', "Couldn't parse firmware-update-check loopup-lists from file.")
|
||||
|
||||
self._callback = callback
|
||||
self._set_download_url_callback = set_download_url_callback
|
||||
|
||||
|
@ -82,11 +83,11 @@ class FirmwareUpdateCheckerJob(Job):
|
|||
|
||||
return result
|
||||
|
||||
def getCurrentVersionForMachine(self, machine_id: MachineId) -> Version:
|
||||
def getCurrentVersionForMachine(self, machine_id: int) -> Version:
|
||||
max_version = self.ZERO_VERSION
|
||||
|
||||
machine_urls = self._urls.get(machine_id)
|
||||
parse_function = self.PARSE_VERSION_URL_PER_MACHINE.get(machine_id)
|
||||
machine_urls = self._check_urls_per_machine.get(machine_id)
|
||||
parse_function = self._parse_version_url_per_machine.get(machine_id)
|
||||
if machine_urls is not None and parse_function is not None:
|
||||
for url in machine_urls:
|
||||
version = parse_function(self.getUrlResponse(url))
|
||||
|
@ -99,7 +100,7 @@ class FirmwareUpdateCheckerJob(Job):
|
|||
return max_version
|
||||
|
||||
def run(self):
|
||||
if not self._urls or self._urls is None:
|
||||
if not self._machine_ids or self._machine_ids is None:
|
||||
Logger.log("e", "Can not check for a new release. URL not set!")
|
||||
return
|
||||
|
||||
|
@ -112,7 +113,7 @@ 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.MACHINE_PER_NAME.get(machine_name.lower())
|
||||
machine_id = self._machine_per_name.get(machine_name.lower())
|
||||
if machine_id is not None:
|
||||
Logger.log("i", "You have a {0} in the printer list. Let's check the firmware!".format(machine_name))
|
||||
|
||||
|
@ -150,7 +151,7 @@ class FirmwareUpdateCheckerJob(Job):
|
|||
|
||||
# If we do this in a cool way, the download url should be available in the JSON file
|
||||
if self._set_download_url_callback:
|
||||
redirect = self.REDIRECT_USER_PER_MACHINE.get(machine_id)
|
||||
redirect = self._redirect_user_per_machine.get(machine_id)
|
||||
if redirect is not None:
|
||||
self._set_download_url_callback(redirect)
|
||||
else:
|
||||
|
|
36
plugins/FirmwareUpdateChecker/resources/machines.json
Normal file
36
plugins/FirmwareUpdateChecker/resources/machines.json
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"_comment": "Multiple 'update_urls': The 'new'-style URL is the only way to check for S5 firmware, and in the future, the UM3 line will also switch over, but for now the old 'JEDI'-style URL is still needed.",
|
||||
|
||||
"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",
|
||||
"version_parser": "default"
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"version_parser": "default"
|
||||
},
|
||||
{
|
||||
"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",
|
||||
"version_parser": "default"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue