--- a/src/eric7/MicroPython/EspDevices.py Wed Feb 08 11:54:36 2023 +0100 +++ b/src/eric7/MicroPython/EspDevices.py Wed Feb 08 18:09:19 2023 +0100 @@ -8,16 +8,17 @@ boards. """ -from PyQt6.QtCore import QProcess, pyqtSlot +from PyQt6.QtCore import QProcess, QUrl, pyqtSlot +from PyQt6.QtNetwork import QNetworkRequest from PyQt6.QtWidgets import QDialog -from eric7 import Preferences +from eric7 import Globals, Preferences from eric7.EricWidgets import EricMessageBox from eric7.EricWidgets.EricApplication import ericApp from eric7.EricWidgets.EricProcessDialog import EricProcessDialog from eric7.SystemUtilities import PythonUtilities -from .MicroPythonDevices import MicroPythonDevice +from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice from .MicroPythonWidget import HAS_QTCHART @@ -125,30 +126,42 @@ @type QMenu """ connected = self.microPython.isConnected() + linkConnected = self.microPython.isLinkConnected() - act = menu.addAction(self.tr("Erase Flash"), self.__eraseFlash) - act.setEnabled(not connected) - act = menu.addAction( + menu.addAction( + self.tr("Show MicroPython Versions"), self.__showFirmwareVersions + ).setEnabled(connected) + menu.addAction(self.tr("Erase Flash"), self.__eraseFlash).setEnabled( + not linkConnected + ) + menu.addAction( self.tr("Flash MicroPython Firmware"), self.__flashMicroPython - ) - act.setEnabled(not connected) + ).setEnabled(not linkConnected) menu.addSeparator() - act = menu.addAction(self.tr("Flash Additional Firmware"), self.__flashAddons) - act.setEnabled(not connected) + menu.addAction( + self.tr("Flash Additional Firmware"), self.__flashAddons + ).setEnabled(not linkConnected) menu.addSeparator() - act = menu.addAction(self.tr("Backup Firmware"), self.__backupFlash) - act.setEnabled(not connected) - act = menu.addAction(self.tr("Restore Firmware"), self.__restoreFlash) - act.setEnabled(not connected) + menu.addAction(self.tr("Backup Firmware"), self.__backupFlash).setEnabled( + not linkConnected + ) + menu.addAction(self.tr("Restore Firmware"), self.__restoreFlash).setEnabled( + not linkConnected + ) menu.addSeparator() - act = menu.addAction(self.tr("Show Chip ID"), self.__showChipID) - act.setEnabled(not connected) - act = menu.addAction(self.tr("Show Flash ID"), self.__showFlashID) - act.setEnabled(not connected) - act = menu.addAction(self.tr("Show MAC Address"), self.__showMACAddress) - act.setEnabled(not connected) + menu.addAction(self.tr("Show Chip ID"), self.__showChipID).setEnabled( + not linkConnected + ) + menu.addAction(self.tr("Show Flash ID"), self.__showFlashID).setEnabled( + not linkConnected + ) + menu.addAction(self.tr("Show MAC Address"), self.__showMACAddress).setEnabled( + not linkConnected + ) menu.addSeparator() - act = menu.addAction(self.tr("Reset Device"), self.__resetDevice) + menu.addAction(self.tr("Reset Device"), self.__resetDevice).setEnabled( + connected or not linkConnected + ) menu.addSeparator() menu.addAction(self.tr("Install 'esptool.py'"), self.__installEspTool) @@ -349,6 +362,74 @@ dlg.exec() @pyqtSlot() + def __showFirmwareVersions(self): + """ + Private slot to show the firmware version of the connected device and the + available firmware version. + """ + if self.microPython.isConnected(): + interface = self.microPython.commandsInterface() + if interface is not None: + impInfo = interface.getImplementation() + if impInfo["name"] != "micropython": + EricMessageBox.critical( + None, + self.tr("Show MicroPython Versions"), + self.tr( + """The firmware of the connected device cannot be""" + """ determined or the board does not run MicroPython.""" + """ Aborting...""" + ), + ) + else: + ui = ericApp().getObject("UserInterface") + request = QNetworkRequest(QUrl(FirmwareGithubUrls["micropython"])) + reply = ui.networkAccessManager().head(request) + reply.finished.connect( + lambda: self.__firmwareVersionResponse(reply, impInfo) + ) + + def __firmwareVersionResponse(self, reply, implementation): + """ + Private method handling the response of the latest version request. + + @param reply reference to the reply object + @type QNetworkReply + @param implementation dictionary containing the implementation data of the + connected device + @type dict + """ + latestUrl = reply.url().toString() + tag = latestUrl.rsplit("/", 1)[-1] + while tag and not tag[0].isdecimal(): + # get rid of leading non-decimal characters + tag = tag[1:] + latestVersion = Globals.versionToTuple(tag) + + if implementation["version"] == "unknown": + currentVersionStr = self.tr("unknown") + currentVersion = (0, 0, 0) + else: + currentVersionStr = implementation["version"] + currentVersion = Globals.versionToTuple(currentVersionStr) + + msg = self.tr( + "<h4>MicroPython Version Information</h4>" + "<table>" + "<tr><td>Installed:</td><td>{0}</td></tr>" + "<tr><td>Available:</td><td>{1}</td></tr>" + "</table>" + ).format(currentVersionStr, tag) + if currentVersion < latestVersion: + msg += self.tr("<p><b>Update available!</b></p>") + + EricMessageBox.information( + None, + self.tr("MicroPython Version"), + msg, + ) + + @pyqtSlot() def __showChipID(self): """ Private slot to show the ID of the ESP chip.