Reorganized the MicroPython package. eric7

Mon, 13 Feb 2023 17:49:52 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 13 Feb 2023 17:49:52 +0100
branch
eric7
changeset 9756
9854647c8c5c
parent 9755
1a09700229e7
child 9757
ab6e87f6f1c4

Reorganized the MicroPython package.

eric7.epj file | annotate | diff | comparison | revisions
src/eric7/APIs/Python3/eric7.api file | annotate | diff | comparison | revisions
src/eric7/APIs/Python3/eric7.bas file | annotate | diff | comparison | revisions
src/eric7/Documentation/Help/source.qch file | annotate | diff | comparison | revisions
src/eric7/Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.DeviceBase.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.EspDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.GenericMicroPythonDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.PyBoardDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.RP2040Devices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.TeensyDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.Devices.__init__.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.EspBackupRestoreFirmwareDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.EspDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.EspFirmwareSelectionDialog.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.GenericMicroPythonDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.MicroPythonDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.MicrobitDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.PyBoardDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.RP2040Devices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/eric7.MicroPython.TeensyDevices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/index-eric7.MicroPython.CircuitPythonUpdater.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/index-eric7.MicroPython.Devices.CircuitPythonUpdater.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/index-eric7.MicroPython.Devices.EspDialogs.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/index-eric7.MicroPython.Devices.html file | annotate | diff | comparison | revisions
src/eric7/Documentation/Source/index-eric7.MicroPython.html file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/CircupFunctions.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/CircuitPythonUpdater/__init__.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/CircupFunctions.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/RequirementsDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/RequirementsDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowBundlesDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowBundlesDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowInstalledDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowInstalledDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowOutdatedDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowOutdatedDialog.ui file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/CircuitPythonUpdater/__init__.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/DeviceBase.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/EspDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/EspDialogs/EspBackupRestoreFirmwareDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/EspDialogs/EspFirmwareSelectionDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/EspDialogs/__init__.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/MicrobitDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/PyBoardDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/RP2040Devices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/TeensyDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/Devices/__init__.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/EspBackupRestoreFirmwareDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/EspDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/EspFirmwareSelectionDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/GenericMicroPythonDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/MicroPythonDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/MicrobitDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/PyBoardDevices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/RP2040Devices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/TeensyDevices.py file | annotate | diff | comparison | revisions
--- a/eric7.epj	Sun Feb 12 18:11:20 2023 +0100
+++ b/eric7.epj	Mon Feb 13 17:49:52 2023 +0100
@@ -333,11 +333,11 @@
       "src/eric7/JediInterface/RefactoringPreviewDialog.ui",
       "src/eric7/MicroPython/AddEditDevicesDialog.ui",
       "src/eric7/MicroPython/BoardDataDialog.ui",
-      "src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.ui",
-      "src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.ui",
-      "src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.ui",
-      "src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.ui",
       "src/eric7/MicroPython/ConnectionSelectionDialog.ui",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/RequirementsDialog.ui",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowBundlesDialog.ui",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowInstalledDialog.ui",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowOutdatedDialog.ui",
       "src/eric7/MicroPython/EspBackupRestoreFirmwareDialog.ui",
       "src/eric7/MicroPython/EspFirmwareSelectionDialog.ui",
       "src/eric7/MicroPython/IgnoredDevicesDialog.ui",
@@ -1280,22 +1280,28 @@
       "src/eric7/JediInterface/__init__.py",
       "src/eric7/MicroPython/AddEditDevicesDialog.py",
       "src/eric7/MicroPython/BoardDataDialog.py",
-      "src/eric7/MicroPython/CircuitPythonDevices.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/CircupFunctions.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.py",
-      "src/eric7/MicroPython/CircuitPythonUpdater/__init__.py",
       "src/eric7/MicroPython/ConnectionSelectionDialog.py",
-      "src/eric7/MicroPython/EspBackupRestoreFirmwareDialog.py",
-      "src/eric7/MicroPython/EspDevices.py",
-      "src/eric7/MicroPython/EspFirmwareSelectionDialog.py",
-      "src/eric7/MicroPython/GenericMicroPythonDevices.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonDevices.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/CircupFunctions.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/RequirementsDialog.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowBundlesDialog.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowInstalledDialog.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowOutdatedDialog.py",
+      "src/eric7/MicroPython/Devices/CircuitPythonUpdater/__init__.py",
+      "src/eric7/MicroPython/Devices/DeviceBase.py",
+      "src/eric7/MicroPython/Devices/EspDevices.py",
+      "src/eric7/MicroPython/Devices/EspDialogs/EspBackupRestoreFirmwareDialog.py",
+      "src/eric7/MicroPython/Devices/EspDialogs/EspFirmwareSelectionDialog.py",
+      "src/eric7/MicroPython/Devices/EspDialogs/__init__.py",
+      "src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py",
+      "src/eric7/MicroPython/Devices/MicrobitDevices.py",
+      "src/eric7/MicroPython/Devices/PyBoardDevices.py",
+      "src/eric7/MicroPython/Devices/RP2040Devices.py",
+      "src/eric7/MicroPython/Devices/TeensyDevices.py",
+      "src/eric7/MicroPython/Devices/__init__.py",
       "src/eric7/MicroPython/IgnoredDevicesDialog.py",
       "src/eric7/MicroPython/MicroPythonCommandsInterface.py",
-      "src/eric7/MicroPython/MicroPythonDevices.py",
       "src/eric7/MicroPython/MicroPythonFileManager.py",
       "src/eric7/MicroPython/MicroPythonFileManagerWidget.py",
       "src/eric7/MicroPython/MicroPythonFileSystemUtilities.py",
@@ -1303,11 +1309,7 @@
       "src/eric7/MicroPython/MicroPythonProgressInfoDialog.py",
       "src/eric7/MicroPython/MicroPythonSerialPort.py",
       "src/eric7/MicroPython/MicroPythonWidget.py",
-      "src/eric7/MicroPython/MicrobitDevices.py",
-      "src/eric7/MicroPython/PyBoardDevices.py",
-      "src/eric7/MicroPython/RP2040Devices.py",
       "src/eric7/MicroPython/ShowModulesDialog.py",
-      "src/eric7/MicroPython/TeensyDevices.py",
       "src/eric7/MicroPython/UF2FlashDialog.py",
       "src/eric7/MicroPython/UnknownDevicesDialog.py",
       "src/eric7/MicroPython/__init__.py",
--- a/src/eric7/APIs/Python3/eric7.api	Sun Feb 12 18:11:20 2023 +0100
+++ b/src/eric7/APIs/Python3/eric7.api	Mon Feb 13 17:49:52 2023 +0100
@@ -2539,94 +2539,191 @@
 eric7.MicroPython.AddEditDevicesDialog.AddEditDevicesDialog.on_reportButton_clicked?4()
 eric7.MicroPython.AddEditDevicesDialog.AddEditDevicesDialog?1(vid=0, pid=0, description=0, deviceData=None, parent=None)
 eric7.MicroPython.BoardDataDialog.BoardDataDialog?1(data, parent=None)
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.DeviceVolumeName?7
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.canRunScript?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.canStartFileManager?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.canStartPlotter?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.canStartRepl?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.deviceName?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.forceInterrupt?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.getDocumentationUrl?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.getDownloadMenuEntries?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.getWorkspace?4(silent=False)
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.hasFlashMenuEntry?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.runScript?4(script)
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.setButtons?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.supportsLocalFileAccess?4()
-eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice?1(microPythonWidget, deviceType, boardName, parent=None)
-eric7.MicroPython.CircuitPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
-eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface.installCircup?4()
-eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface.populateMenu?4(menu)
-eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface?1(device, parent=None)
-eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.isCircupAvailable?4()
-eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.ensure_latest_bundle?4(bundle)
-eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.find_modules?4(device_path, bundles_list)
-eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.get_circuitpython_version?4(device_path)
-eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.install_module?4(device_path, device_modules, name, py, mod_names)
-eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.patch_circup?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_buttonBox_clicked?4(button)
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_copyButton_clicked?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_insertButton_clicked?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_replaceAllButton_clicked?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_replaceSelectionButton_clicked?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_requirementsEdit_textChanged?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_requirementsFilePicker_textChanged?4(txt)
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_saveButton_clicked?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_saveToButton_clicked?4()
-eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog?1(devicePath, parent=None)
-eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.ShowBundlesDialog?1(withModules, parent=None)
-eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.ShowInstalledDialog?1(devicePath, parent=None)
-eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.getSelection?4()
-eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.on_modulesList_itemChanged?4(item, column)
-eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog?1(devicePath, selectionMode=False, parent=None)
 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.PortNameRole?7
 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.VidPidRole?7
 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.getData?4()
 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.on_deviceTypeComboBox_currentTextChanged?4(txt)
 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.on_portNameComboBox_currentTextChanged?4(txt)
 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog?1(ports, currentPort, currentType, parent=None)
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.Chips?7
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.FlashModes?7
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.FlashSizes?7
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.getData?4()
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged?4(chip)
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged?4(firmware)
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged?4(size)
-eric7.MicroPython.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog?1(backupMode=True, parent=None)
-eric7.MicroPython.EspDevices.EspDevice.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.EspDevices.EspDevice.canRunScript?4()
-eric7.MicroPython.EspDevices.EspDevice.canStartFileManager?4()
-eric7.MicroPython.EspDevices.EspDevice.canStartPlotter?4()
-eric7.MicroPython.EspDevices.EspDevice.canStartRepl?4()
-eric7.MicroPython.EspDevices.EspDevice.deviceName?4()
-eric7.MicroPython.EspDevices.EspDevice.forceInterrupt?4()
-eric7.MicroPython.EspDevices.EspDevice.getDocumentationUrl?4()
-eric7.MicroPython.EspDevices.EspDevice.getFirmwareUrl?4()
-eric7.MicroPython.EspDevices.EspDevice.hasFlashMenuEntry?4()
-eric7.MicroPython.EspDevices.EspDevice.runScript?4(script)
-eric7.MicroPython.EspDevices.EspDevice.setButtons?4()
-eric7.MicroPython.EspDevices.EspDevice?1(microPythonWidget, deviceType, parent=None)
-eric7.MicroPython.EspDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.Chips?7
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.FlashAddresses?7
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.FlashModes?7
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.getData?4()
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.on_addressEdit_textChanged?4(address)
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged?4(chip)
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.on_firmwarePicker_textChanged?4(firmware)
-eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog?1(addon=False, parent=None)
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.canRunScript?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.canStartFileManager?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.canStartPlotter?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.canStartRepl?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.deviceName?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.getWorkspace?4(silent=False)
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.runScript?4(script)
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.setButtons?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.supportsLocalFileAccess?4()
-eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice?1(microPythonWidget, deviceType, vid, pid, parent=None)
-eric7.MicroPython.GenericMicroPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.DeviceVolumeName?7
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.canRunScript?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.canStartRepl?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.deviceName?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.forceInterrupt?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.getDocumentationUrl?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.getDownloadMenuEntries?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.getWorkspace?4(silent=False)
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.hasFlashMenuEntry?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.runScript?4(script)
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.setButtons?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice.supportsLocalFileAccess?4()
+eric7.MicroPython.Devices.CircuitPythonDevices.CircuitPythonDevice?1(microPythonWidget, deviceType, boardName, parent=None)
+eric7.MicroPython.Devices.CircuitPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface.installCircup?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface.populateMenu?4(menu)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface?1(device, parent=None)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.isCircupAvailable?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.ensure_latest_bundle?4(bundle)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.find_modules?4(device_path, bundles_list)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.get_circuitpython_version?4(device_path)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.install_module?4(device_path, device_modules, name, py, mod_names)
+eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.patch_circup?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_buttonBox_clicked?4(button)
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_copyButton_clicked?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_insertButton_clicked?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_replaceAllButton_clicked?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_replaceSelectionButton_clicked?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_requirementsEdit_textChanged?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_requirementsFilePicker_textChanged?4(txt)
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_saveButton_clicked?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_saveToButton_clicked?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog?1(devicePath, parent=None)
+eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.ShowBundlesDialog?1(withModules, parent=None)
+eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.ShowInstalledDialog?1(devicePath, parent=None)
+eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.getSelection?4()
+eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.on_modulesList_itemChanged?4(item, column)
+eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog?1(devicePath, selectionMode=False, parent=None)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.canRunScript?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.canStartRepl?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.checkDeviceData?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.deviceName?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.downloadFirmware?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.forceInterrupt?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.getDeviceData?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.getDeviceType?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.getDocumentationUrl?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.getDownloadMenuEntries?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.getFirmwareUrl?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.getWorkspace?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.handleDataFlood?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.hasDocumentationUrl?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.hasFirmwareUrl?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.hasFlashMenuEntry?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.hasTimeCommands?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.runScript?4(script)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.selectDeviceDirectory?4(deviceDirectories)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.sendCommands?4(commandsList)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.setButtons?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.setConnected?4(connected)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.setFileManager?4(on)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.setPlotter?4(on)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.setRepl?4(on)
+eric7.MicroPython.Devices.DeviceBase.BaseDevice.supportsLocalFileAccess?4()
+eric7.MicroPython.Devices.DeviceBase.BaseDevice?1(microPythonWidget, deviceType, parent=None)
+eric7.MicroPython.Devices.EspDevices.EspDevice.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.EspDevices.EspDevice.canRunScript?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.canStartRepl?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.deviceName?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.forceInterrupt?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.getDocumentationUrl?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.getFirmwareUrl?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.hasFlashMenuEntry?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice.runScript?4(script)
+eric7.MicroPython.Devices.EspDevices.EspDevice.setButtons?4()
+eric7.MicroPython.Devices.EspDevices.EspDevice?1(microPythonWidget, deviceType, parent=None)
+eric7.MicroPython.Devices.EspDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.Chips?7
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.FlashModes?7
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.FlashSizes?7
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.getData?4()
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged?4(chip)
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged?4(firmware)
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged?4(size)
+eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.EspBackupRestoreFirmwareDialog?1(backupMode=True, parent=None)
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.Chips?7
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.FlashAddresses?7
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.FlashModes?7
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.getData?4()
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.on_addressEdit_textChanged?4(address)
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged?4(chip)
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.on_firmwarePicker_textChanged?4(firmware)
+eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog?1(addon=False, parent=None)
+eric7.MicroPython.Devices.FirmwareGithubUrls?7
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.canRunScript?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.canStartRepl?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.deviceName?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.getWorkspace?4(silent=False)
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.runScript?4(script)
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.setButtons?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice.supportsLocalFileAccess?4()
+eric7.MicroPython.Devices.GenericMicroPythonDevices.GenericMicroPythonDevice?1(microPythonWidget, deviceType, vid, pid, parent=None)
+eric7.MicroPython.Devices.GenericMicroPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.IgnoredBoards?7
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.canRunScript?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.canStartRepl?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.deviceName?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.forceInterrupt?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDocumentationUrl?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDownloadMenuEntries?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.hasFlashMenuEntry?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.hasTimeCommands?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.runScript?4(script)
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.setButtons?4()
+eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice?1(microPythonWidget, deviceType, serialNumber, parent=None)
+eric7.MicroPython.Devices.MicrobitDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.DeviceVolumeName?7
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.FlashInstructionsURL?7
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.canRunScript?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.canStartRepl?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.deviceName?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.forceInterrupt?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.getDocumentationUrl?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.getFirmwareUrl?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.getWorkspace?4(silent=False)
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.hasFlashMenuEntry?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.runScript?4(script)
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.setButtons?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice.supportsLocalFileAccess?4()
+eric7.MicroPython.Devices.PyBoardDevices.PyBoardDevice?1(microPythonWidget, deviceType, parent=None)
+eric7.MicroPython.Devices.PyBoardDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.canRunScript?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.canStartFileManager?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.canStartPlotter?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.canStartRepl?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.deviceName?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.forceInterrupt?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.getDocumentationUrl?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.getDownloadMenuEntries?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.hasFlashMenuEntry?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.runScript?4(script)
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device.setButtons?4()
+eric7.MicroPython.Devices.RP2040Devices.RP2040Device?1(microPythonWidget, deviceType, parent=None)
+eric7.MicroPython.Devices.RP2040Devices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.SupportedBoards?7
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.addDeviceMenuEntries?4(menu)
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.canRunScript?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.canStartFileManager?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.canStartPlotter?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.canStartRepl?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.deviceName?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.forceInterrupt?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.getDocumentationUrl?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.getFirmwareUrl?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.runScript?4(script)
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice.setButtons?4()
+eric7.MicroPython.Devices.TeensyDevices.TeensyDevice?1(microPythonWidget, deviceType, parent=None)
+eric7.MicroPython.Devices.TeensyDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
+eric7.MicroPython.Devices.getDevice?4(deviceType, microPythonWidget, vid, pid, boardName="", serialNumber="")
+eric7.MicroPython.Devices.getDeviceIcon?4(boardName, iconFormat=True)
+eric7.MicroPython.Devices.getFoundDevices?4()
+eric7.MicroPython.Devices.getSupportedDevices?4()
 eric7.MicroPython.IgnoredDevicesDialog.IgnoredDevicesDialog.getDevices?4()
 eric7.MicroPython.IgnoredDevicesDialog.IgnoredDevicesDialog?1(deviceList, parent=None)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.cd?4(dirname)
@@ -2639,6 +2736,7 @@
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.fileSystemInfo?4()
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.get?4(deviceFileName, hostFileName=None)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.getBoardInformation?4()
+eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.getData?4(deviceFileName)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.getDeviceData?4()
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.getModules?4()
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.getTime?4()
@@ -2649,6 +2747,7 @@
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.mkdir?4(dirname)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.probeDevice?4()
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.put?4(hostFileName, deviceFileName=None)
+eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.putData?4(deviceFileName, content)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.pwd?4()
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.remainingTask?4()
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.rm?4(filename)
@@ -2657,43 +2756,6 @@
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.syncTime?4(deviceType, hasCPy=False)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.write?4(data)
 eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface?1(parent=None)
-eric7.MicroPython.MicroPythonDevices.FirmwareGithubUrls?7
-eric7.MicroPython.MicroPythonDevices.IgnoredBoards?7
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.canRunScript?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.canStartFileManager?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.canStartPlotter?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.canStartRepl?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.checkDeviceData?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.deviceName?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.downloadFirmware?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.forceInterrupt?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.getDeviceData?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.getDeviceType?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.getDocumentationUrl?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.getDownloadMenuEntries?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.getFirmwareUrl?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.getWorkspace?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.handleDataFlood?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.hasDocumentationUrl?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.hasFirmwareUrl?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.hasFlashMenuEntry?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.hasTimeCommands?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.runScript?4(script)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.selectDeviceDirectory?4(deviceDirectories)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.sendCommands?4(commandsList)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.setButtons?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.setConnected?4(connected)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.setFileManager?4(on)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.setPlotter?4(on)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.setRepl?4(on)
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.supportsLocalFileAccess?4()
-eric7.MicroPython.MicroPythonDevices.MicroPythonDevice?1(microPythonWidget, deviceType, parent=None)
-eric7.MicroPython.MicroPythonDevices.SupportedBoards?7
-eric7.MicroPython.MicroPythonDevices.getDevice?4(deviceType, microPythonWidget, vid, pid, boardName="", serialNumber="")
-eric7.MicroPython.MicroPythonDevices.getDeviceIcon?4(boardName, iconFormat=True)
-eric7.MicroPython.MicroPythonDevices.getFoundDevices?4()
-eric7.MicroPython.MicroPythonDevices.getSupportedDevices?4()
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.cd?4(dirname)
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.createDirectoryDone?7
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.currentDir?7
@@ -2704,11 +2766,14 @@
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.fileSystemInfo?4()
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.fsinfoDone?7
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.get?4(deviceFileName, hostFileName="")
+eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.getData?4(deviceFileName)
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.getFileDone?7
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.lls?4(dirname, showHidden=False)
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.longListFiles?7
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.mkdir?4(dirname)
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.put?4(hostFileName, deviceFileName="")
+eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.putData?4(deviceFileName, data)
+eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.putDataDone?7
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.putFileDone?7
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.pwd?4()
 eric7.MicroPython.MicroPythonFileManager.MicroPythonFileManager.removeDirectoryDone?7
@@ -2729,8 +2794,11 @@
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_localHomeButton_clicked?4()
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_localReloadButton_clicked?4()
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_localUpButton_clicked?4()
+eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_openButton_clicked?4()
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_putAsButton_clicked?4()
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_putButton_clicked?4(putAs=False)
+eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_saveAsButton_clicked?4()
+eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_saveButton_clicked?4(saveAs=False)
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.on_syncButton_clicked?4()
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.start?4()
 eric7.MicroPython.MicroPythonFileManagerWidget.MicroPythonFileManagerWidget.stop?4()
@@ -2790,69 +2858,9 @@
 eric7.MicroPython.MicroPythonWidget.MicroPythonWidget.on_saveButton_clicked?4()
 eric7.MicroPython.MicroPythonWidget.MicroPythonWidget.setActionButtons?4(**kwargs)
 eric7.MicroPython.MicroPythonWidget.MicroPythonWidget?1(parent=None)
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.canRunScript?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.canStartFileManager?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.canStartPlotter?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.canStartRepl?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.deviceName?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.forceInterrupt?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.getDocumentationUrl?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.getDownloadMenuEntries?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.hasFlashMenuEntry?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.hasTimeCommands?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.runScript?4(script)
-eric7.MicroPython.MicrobitDevices.MicrobitDevice.setButtons?4()
-eric7.MicroPython.MicrobitDevices.MicrobitDevice?1(microPythonWidget, deviceType, serialNumber, parent=None)
-eric7.MicroPython.MicrobitDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.DeviceVolumeName?7
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.FlashInstructionsURL?7
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.canRunScript?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.canStartFileManager?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.canStartPlotter?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.canStartRepl?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.deviceName?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.forceInterrupt?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.getDocumentationUrl?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.getFirmwareUrl?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.getWorkspace?4(silent=False)
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.hasFlashMenuEntry?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.runScript?4(script)
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.setButtons?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice.supportsLocalFileAccess?4()
-eric7.MicroPython.PyBoardDevices.PyBoardDevice?1(microPythonWidget, deviceType, parent=None)
-eric7.MicroPython.PyBoardDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
-eric7.MicroPython.RP2040Devices.RP2040Device.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.RP2040Devices.RP2040Device.canRunScript?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.canStartFileManager?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.canStartPlotter?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.canStartRepl?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.deviceName?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.forceInterrupt?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.getDocumentationUrl?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.getDownloadMenuEntries?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.hasFlashMenuEntry?4()
-eric7.MicroPython.RP2040Devices.RP2040Device.runScript?4(script)
-eric7.MicroPython.RP2040Devices.RP2040Device.setButtons?4()
-eric7.MicroPython.RP2040Devices.RP2040Device?1(microPythonWidget, deviceType, parent=None)
-eric7.MicroPython.RP2040Devices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
 eric7.MicroPython.ShowModulesDialog.ShowModulesDialog.getSelection?4()
 eric7.MicroPython.ShowModulesDialog.ShowModulesDialog.on_modulesList_itemChanged?4(item)
 eric7.MicroPython.ShowModulesDialog.ShowModulesDialog?1(modulesList, selectionMode=False, info="", parent=None)
-eric7.MicroPython.TeensyDevices.TeensyDevice.addDeviceMenuEntries?4(menu)
-eric7.MicroPython.TeensyDevices.TeensyDevice.canRunScript?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.canStartFileManager?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.canStartPlotter?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.canStartRepl?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.deviceName?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.forceInterrupt?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.getDocumentationUrl?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.getFirmwareUrl?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice.runScript?4(script)
-eric7.MicroPython.TeensyDevices.TeensyDevice.setButtons?4()
-eric7.MicroPython.TeensyDevices.TeensyDevice?1(microPythonWidget, deviceType, parent=None)
-eric7.MicroPython.TeensyDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName, serialNumber)
 eric7.MicroPython.UF2FlashDialog.SupportedUF2Boards?7
 eric7.MicroPython.UF2FlashDialog.UF2FlashDialog.DeviceTypeRole?7
 eric7.MicroPython.UF2FlashDialog.UF2FlashDialog.DeviceVidPidRole?7
@@ -8214,11 +8222,13 @@
 eric7.QScintilla.Editor.Editor.changeEvent?4(evt)
 eric7.QScintilla.Editor.Editor.changeMarkersUpdated?7
 eric7.QScintilla.Editor.Editor.checkDirty?4()
+eric7.QScintilla.Editor.Editor.checkReadOnly?4()
 eric7.QScintilla.Editor.Editor.checkSpelling?4()
 eric7.QScintilla.Editor.Editor.checkSyntax?4()
 eric7.QScintilla.Editor.Editor.clearAllHighlights?4()
 eric7.QScintilla.Editor.Editor.clearBookmarks?4()
 eric7.QScintilla.Editor.Editor.clearBreakpoint?4(line)
+eric7.QScintilla.Editor.Editor.clearChangeMarkers?4()
 eric7.QScintilla.Editor.Editor.clearFlakesWarnings?4()
 eric7.QScintilla.Editor.Editor.clearHighlight?4(startLine, startIndex, endLine, endIndex)
 eric7.QScintilla.Editor.Editor.clearSearchIndicators?4()
@@ -8321,6 +8331,7 @@
 eric7.QScintilla.Editor.Editor.isCythonFile?4()
 eric7.QScintilla.Editor.Editor.isJavascriptFile?4()
 eric7.QScintilla.Editor.Editor.isLastEditPositionAvailable?4()
+eric7.QScintilla.Editor.Editor.isLocalFile?4()
 eric7.QScintilla.Editor.Editor.isMicroPythonFile?4()
 eric7.QScintilla.Editor.Editor.isPy3File?4()
 eric7.QScintilla.Editor.Editor.isPyFile?4()
@@ -8388,6 +8399,7 @@
 eric7.QScintilla.Editor.Editor.sendSharedEdit?4()
 eric7.QScintilla.Editor.Editor.setAutoCompletionEnabled?4(enable)
 eric7.QScintilla.Editor.Editor.setAutoSpellChecking?4()
+eric7.QScintilla.Editor.Editor.setFileName?4(name)
 eric7.QScintilla.Editor.Editor.setHighlight?4(startLine, startIndex, endLine, endIndex)
 eric7.QScintilla.Editor.Editor.setLanguage?4(filename, initTextDisplay=True, propagate=True, pyname="")
 eric7.QScintilla.Editor.Editor.setMonospaced?4(on)
@@ -10943,6 +10955,7 @@
 eric7.ViewManager.ViewManager.ViewManager.mainWidget?4()
 eric7.ViewManager.ViewManager.ViewManager.newEditor?4()
 eric7.ViewManager.ViewManager.ViewManager.newEditorView?4(fn, caller, filetype="", indexes=None)
+eric7.ViewManager.ViewManager.ViewManager.newEditorWithText?4(text, language="", fileName="")
 eric7.ViewManager.ViewManager.ViewManager.nextSplit?4()
 eric7.ViewManager.ViewManager.ViewManager.openFiles?4(prog)
 eric7.ViewManager.ViewManager.ViewManager.openSourceFile?4(fn, lineno=-1, filetype="", selStart=0, selEnd=0, pos=0, addNext=False, indexes=None, )
--- a/src/eric7/APIs/Python3/eric7.bas	Sun Feb 12 18:11:20 2023 +0100
+++ b/src/eric7/APIs/Python3/eric7.bas	Mon Feb 13 17:49:52 2023 +0100
@@ -38,6 +38,7 @@
 AutoSaver QObject
 AutoScroller QObject
 BackgroundService QTcpServer
+BaseDevice QObject
 BinaryModel QAbstractTableModel
 BlackConfigurationDialog QDialog Ui_BlackConfigurationDialog
 BlackFormattingAction enum.Enum
@@ -79,7 +80,7 @@
 ChangeBookmarkCommand QUndoCommand
 ChatWidget QWidget Ui_ChatWidget
 ChromeImporter BookmarksImporter
-CircuitPythonDevice MicroPythonDevice
+CircuitPythonDevice BaseDevice
 CircuitPythonUpdaterInterface QObject
 Class ClbrBaseClasses.Class VisibilityMixin
 ClassDecoratorType enum.Enum
@@ -322,7 +323,7 @@
 EricdocPlugin QObject
 ErrorLogDialog QDialog Ui_ErrorLogDialog
 EspBackupRestoreFirmwareDialog QDialog Ui_EspBackupRestoreFirmwareDialog
-EspDevice MicroPythonDevice
+EspDevice BaseDevice
 EspFirmwareSelectionDialog QDialog Ui_EspFirmwareSelectionDialog
 ExceptionLogger QTreeWidget
 ExceptionsFilterDialog QDialog Ui_ExceptionsFilterDialog
@@ -361,7 +362,7 @@
 Function ClbrBaseClasses.Function VisibilityMixin
 FunctionType enum.Enum
 FunctionVisitor ast.NodeVisitor
-GenericMicroPythonDevice MicroPythonDevice
+GenericMicroPythonDevice BaseDevice
 Git VersionControl
 GitAddRemoteDialog QDialog Ui_GitAddRemoteDialog
 GitApplyBundleDataDialog QDialog Ui_GitApplyBundleDataDialog
@@ -649,7 +650,6 @@
 MessageBoxWizard QObject
 MessageBoxWizardDialog QDialog Ui_MessageBoxWizardDialog
 MicroPythonCommandsInterface QObject
-MicroPythonDevice QObject
 MicroPythonFileManager QObject
 MicroPythonFileManagerWidget QWidget Ui_MicroPythonFileManagerWidget
 MicroPythonGraphWidget QWidget
@@ -657,7 +657,7 @@
 MicroPythonProgressInfoDialog QDialog Ui_MicroPythonProgressInfoDialog
 MicroPythonSerialPort QSerialPort
 MicroPythonWidget QWidget Ui_MicroPythonWidget
-MicrobitDevice MicroPythonDevice
+MicrobitDevice BaseDevice
 MicrosoftEngine TranslationEngine
 MimeTypesPage ConfigurationPageBase Ui_MimeTypesPage
 MiniEditor EricMainWindow
@@ -805,7 +805,7 @@
 ProtocolHandlerManagerDialog QDialog Ui_ProtocolHandlerManagerDialog
 Purge HgExtension
 PurgeProjectHelper HgExtensionProjectHelper
-PyBoardDevice MicroPythonDevice
+PyBoardDevice BaseDevice
 PyCoverageDialog QDialog Ui_PyCoverageDialog
 PyCoverageHtmlReportDialog QDialog Ui_PyCoverageHtmlReportDialog
 PyCoverageJsonReportDialog QDialog Ui_PyCoverageJsonReportDialog
@@ -846,7 +846,7 @@
 Queues HgExtension
 QueuesProjectHelper HgExtensionProjectHelper
 QuickFindFileDialog QWidget Ui_QuickFindFile
-RP2040Device MicroPythonDevice
+RP2040Device BaseDevice
 RbModule Class
 RccCompilerOptionsDialog QDialog Ui_RccCompilerOptionsDialog
 Rebase HgExtension
@@ -1004,7 +1004,7 @@
 TasksFile QObject
 TasksPage ConfigurationPageBase Ui_TasksPage
 TasksReader XMLStreamReaderBase
-TeensyDevice MicroPythonDevice
+TeensyDevice BaseDevice
 TemplateEntry QTreeWidgetItem
 TemplateGroup QTreeWidgetItem
 TemplateMultipleVariablesDialog QDialog
Binary file src/eric7/Documentation/Help/source.qch has changed
--- a/src/eric7/Documentation/Help/source.qhp	Sun Feb 12 18:11:20 2023 +0100
+++ b/src/eric7/Documentation/Help/source.qhp	Mon Feb 13 17:49:52 2023 +0100
@@ -267,25 +267,34 @@
             <section title="eric7.JediInterface.RefactoringPreviewDialog" ref="eric7.JediInterface.RefactoringPreviewDialog.html" />
           </section>
           <section title="eric7.MicroPython" ref="index-eric7.MicroPython.html">
-            <section title="eric7.MicroPython.CircuitPythonUpdater" ref="index-eric7.MicroPython.CircuitPythonUpdater.html">
-              <section title="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html" />
-              <section title="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html" />
-              <section title="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html" />
-              <section title="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html" />
-              <section title="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html" />
-              <section title="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html" />
+            <section title="eric7.MicroPython.Devices" ref="index-eric7.MicroPython.Devices.html">
+              <section title="eric7.MicroPython.Devices.CircuitPythonUpdater" ref="index-eric7.MicroPython.Devices.CircuitPythonUpdater.html">
+                <section title="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html" />
+                <section title="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html" />
+                <section title="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html" />
+                <section title="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html" />
+                <section title="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html" />
+                <section title="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html" />
+              </section>
+              <section title="eric7.MicroPython.Devices.EspDialogs" ref="index-eric7.MicroPython.Devices.EspDialogs.html">
+                <section title="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html" />
+                <section title="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html" />
+              </section>
+              <section title="eric7.MicroPython.Devices.CircuitPythonDevices" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html" />
+              <section title="eric7.MicroPython.Devices.DeviceBase" ref="eric7.MicroPython.Devices.DeviceBase.html" />
+              <section title="eric7.MicroPython.Devices.EspDevices" ref="eric7.MicroPython.Devices.EspDevices.html" />
+              <section title="eric7.MicroPython.Devices.GenericMicroPythonDevices" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html" />
+              <section title="eric7.MicroPython.Devices.MicrobitDevices" ref="eric7.MicroPython.Devices.MicrobitDevices.html" />
+              <section title="eric7.MicroPython.Devices.PyBoardDevices" ref="eric7.MicroPython.Devices.PyBoardDevices.html" />
+              <section title="eric7.MicroPython.Devices.RP2040Devices" ref="eric7.MicroPython.Devices.RP2040Devices.html" />
+              <section title="eric7.MicroPython.Devices.TeensyDevices" ref="eric7.MicroPython.Devices.TeensyDevices.html" />
+              <section title="eric7.MicroPython.Devices.__init__" ref="eric7.MicroPython.Devices.__init__.html" />
             </section>
             <section title="eric7.MicroPython.AddEditDevicesDialog" ref="eric7.MicroPython.AddEditDevicesDialog.html" />
             <section title="eric7.MicroPython.BoardDataDialog" ref="eric7.MicroPython.BoardDataDialog.html" />
-            <section title="eric7.MicroPython.CircuitPythonDevices" ref="eric7.MicroPython.CircuitPythonDevices.html" />
             <section title="eric7.MicroPython.ConnectionSelectionDialog" ref="eric7.MicroPython.ConnectionSelectionDialog.html" />
-            <section title="eric7.MicroPython.EspBackupRestoreFirmwareDialog" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html" />
-            <section title="eric7.MicroPython.EspDevices" ref="eric7.MicroPython.EspDevices.html" />
-            <section title="eric7.MicroPython.EspFirmwareSelectionDialog" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html" />
-            <section title="eric7.MicroPython.GenericMicroPythonDevices" ref="eric7.MicroPython.GenericMicroPythonDevices.html" />
             <section title="eric7.MicroPython.IgnoredDevicesDialog" ref="eric7.MicroPython.IgnoredDevicesDialog.html" />
             <section title="eric7.MicroPython.MicroPythonCommandsInterface" ref="eric7.MicroPython.MicroPythonCommandsInterface.html" />
-            <section title="eric7.MicroPython.MicroPythonDevices" ref="eric7.MicroPython.MicroPythonDevices.html" />
             <section title="eric7.MicroPython.MicroPythonFileManager" ref="eric7.MicroPython.MicroPythonFileManager.html" />
             <section title="eric7.MicroPython.MicroPythonFileManagerWidget" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html" />
             <section title="eric7.MicroPython.MicroPythonFileSystemUtilities" ref="eric7.MicroPython.MicroPythonFileSystemUtilities.html" />
@@ -293,11 +302,7 @@
             <section title="eric7.MicroPython.MicroPythonProgressInfoDialog" ref="eric7.MicroPython.MicroPythonProgressInfoDialog.html" />
             <section title="eric7.MicroPython.MicroPythonSerialPort" ref="eric7.MicroPython.MicroPythonSerialPort.html" />
             <section title="eric7.MicroPython.MicroPythonWidget" ref="eric7.MicroPython.MicroPythonWidget.html" />
-            <section title="eric7.MicroPython.MicrobitDevices" ref="eric7.MicroPython.MicrobitDevices.html" />
-            <section title="eric7.MicroPython.PyBoardDevices" ref="eric7.MicroPython.PyBoardDevices.html" />
-            <section title="eric7.MicroPython.RP2040Devices" ref="eric7.MicroPython.RP2040Devices.html" />
             <section title="eric7.MicroPython.ShowModulesDialog" ref="eric7.MicroPython.ShowModulesDialog.html" />
-            <section title="eric7.MicroPython.TeensyDevices" ref="eric7.MicroPython.TeensyDevices.html" />
             <section title="eric7.MicroPython.UF2FlashDialog" ref="eric7.MicroPython.UF2FlashDialog.html" />
             <section title="eric7.MicroPython.UnknownDevicesDialog" ref="eric7.MicroPython.UnknownDevicesDialog.html" />
           </section>
@@ -2037,6 +2042,37 @@
       <keyword name="BackgroundService.serviceConnect" id="BackgroundService.serviceConnect" ref="eric7.Utilities.BackgroundService.html#BackgroundService.serviceConnect" />
       <keyword name="BackgroundService.serviceDisconnect" id="BackgroundService.serviceDisconnect" ref="eric7.Utilities.BackgroundService.html#BackgroundService.serviceDisconnect" />
       <keyword name="BackgroundService.shutdown" id="BackgroundService.shutdown" ref="eric7.Utilities.BackgroundService.html#BackgroundService.shutdown" />
+      <keyword name="BaseDevice" id="BaseDevice" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice" />
+      <keyword name="BaseDevice (Constructor)" id="BaseDevice (Constructor)" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.__init__" />
+      <keyword name="BaseDevice.addDeviceMenuEntries" id="BaseDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.addDeviceMenuEntries" />
+      <keyword name="BaseDevice.canRunScript" id="BaseDevice.canRunScript" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.canRunScript" />
+      <keyword name="BaseDevice.canStartFileManager" id="BaseDevice.canStartFileManager" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.canStartFileManager" />
+      <keyword name="BaseDevice.canStartPlotter" id="BaseDevice.canStartPlotter" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.canStartPlotter" />
+      <keyword name="BaseDevice.canStartRepl" id="BaseDevice.canStartRepl" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.canStartRepl" />
+      <keyword name="BaseDevice.checkDeviceData" id="BaseDevice.checkDeviceData" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.checkDeviceData" />
+      <keyword name="BaseDevice.deviceName" id="BaseDevice.deviceName" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.deviceName" />
+      <keyword name="BaseDevice.downloadFirmware" id="BaseDevice.downloadFirmware" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.downloadFirmware" />
+      <keyword name="BaseDevice.forceInterrupt" id="BaseDevice.forceInterrupt" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.forceInterrupt" />
+      <keyword name="BaseDevice.getDeviceData" id="BaseDevice.getDeviceData" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.getDeviceData" />
+      <keyword name="BaseDevice.getDeviceType" id="BaseDevice.getDeviceType" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.getDeviceType" />
+      <keyword name="BaseDevice.getDocumentationUrl" id="BaseDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.getDocumentationUrl" />
+      <keyword name="BaseDevice.getDownloadMenuEntries" id="BaseDevice.getDownloadMenuEntries" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.getDownloadMenuEntries" />
+      <keyword name="BaseDevice.getFirmwareUrl" id="BaseDevice.getFirmwareUrl" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.getFirmwareUrl" />
+      <keyword name="BaseDevice.getWorkspace" id="BaseDevice.getWorkspace" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.getWorkspace" />
+      <keyword name="BaseDevice.handleDataFlood" id="BaseDevice.handleDataFlood" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.handleDataFlood" />
+      <keyword name="BaseDevice.hasDocumentationUrl" id="BaseDevice.hasDocumentationUrl" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.hasDocumentationUrl" />
+      <keyword name="BaseDevice.hasFirmwareUrl" id="BaseDevice.hasFirmwareUrl" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.hasFirmwareUrl" />
+      <keyword name="BaseDevice.hasFlashMenuEntry" id="BaseDevice.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.hasFlashMenuEntry" />
+      <keyword name="BaseDevice.hasTimeCommands" id="BaseDevice.hasTimeCommands" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.hasTimeCommands" />
+      <keyword name="BaseDevice.runScript" id="BaseDevice.runScript" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.runScript" />
+      <keyword name="BaseDevice.selectDeviceDirectory" id="BaseDevice.selectDeviceDirectory" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.selectDeviceDirectory" />
+      <keyword name="BaseDevice.sendCommands" id="BaseDevice.sendCommands" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.sendCommands" />
+      <keyword name="BaseDevice.setButtons" id="BaseDevice.setButtons" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.setButtons" />
+      <keyword name="BaseDevice.setConnected" id="BaseDevice.setConnected" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.setConnected" />
+      <keyword name="BaseDevice.setFileManager" id="BaseDevice.setFileManager" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.setFileManager" />
+      <keyword name="BaseDevice.setPlotter" id="BaseDevice.setPlotter" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.setPlotter" />
+      <keyword name="BaseDevice.setRepl" id="BaseDevice.setRepl" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.setRepl" />
+      <keyword name="BaseDevice.supportsLocalFileAccess" id="BaseDevice.supportsLocalFileAccess" ref="eric7.MicroPython.Devices.DeviceBase.html#BaseDevice.supportsLocalFileAccess" />
       <keyword name="BaseDocstringGenerator" id="BaseDocstringGenerator" ref="eric7.QScintilla.DocstringGenerator.BaseDocstringGenerator.html#BaseDocstringGenerator" />
       <keyword name="BaseDocstringGenerator (Constructor)" id="BaseDocstringGenerator (Constructor)" ref="eric7.QScintilla.DocstringGenerator.BaseDocstringGenerator.html#BaseDocstringGenerator.__init__" />
       <keyword name="BaseDocstringGenerator (Module)" id="BaseDocstringGenerator (Module)" ref="eric7.QScintilla.DocstringGenerator.BaseDocstringGenerator.html" />
@@ -2692,58 +2728,58 @@
       <keyword name="ChromeImporter.importedBookmarks" id="ChromeImporter.importedBookmarks" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.ChromeImporter.html#ChromeImporter.importedBookmarks" />
       <keyword name="ChromeImporter.open" id="ChromeImporter.open" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.ChromeImporter.html#ChromeImporter.open" />
       <keyword name="ChromeImporter.setPath" id="ChromeImporter.setPath" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.ChromeImporter.html#ChromeImporter.setPath" />
-      <keyword name="CircuitPythonDevice" id="CircuitPythonDevice" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice" />
-      <keyword name="CircuitPythonDevice (Constructor)" id="CircuitPythonDevice (Constructor)" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__init__" />
-      <keyword name="CircuitPythonDevice.__aboutToShowLibraryMenu" id="CircuitPythonDevice.__aboutToShowLibraryMenu" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__aboutToShowLibraryMenu" />
-      <keyword name="CircuitPythonDevice.__cpyVersionResponse" id="CircuitPythonDevice.__cpyVersionResponse" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__cpyVersionResponse" />
-      <keyword name="CircuitPythonDevice.__createCPyMenu" id="CircuitPythonDevice.__createCPyMenu" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__createCPyMenu" />
-      <keyword name="CircuitPythonDevice.__deviceVolumeMounted" id="CircuitPythonDevice.__deviceVolumeMounted" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__deviceVolumeMounted" />
-      <keyword name="CircuitPythonDevice.__findDeviceDirectories" id="CircuitPythonDevice.__findDeviceDirectories" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__findDeviceDirectories" />
-      <keyword name="CircuitPythonDevice.__findWorkspace" id="CircuitPythonDevice.__findWorkspace" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__findWorkspace" />
-      <keyword name="CircuitPythonDevice.__flashCircuitPython" id="CircuitPythonDevice.__flashCircuitPython" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__flashCircuitPython" />
-      <keyword name="CircuitPythonDevice.__installLibraryFiles" id="CircuitPythonDevice.__installLibraryFiles" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__installLibraryFiles" />
-      <keyword name="CircuitPythonDevice.__showCircuitPythonVersions" id="CircuitPythonDevice.__showCircuitPythonVersions" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__showCircuitPythonVersions" />
-      <keyword name="CircuitPythonDevice.__showTeensyFlashInstructions" id="CircuitPythonDevice.__showTeensyFlashInstructions" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__showTeensyFlashInstructions" />
-      <keyword name="CircuitPythonDevice.__startTeensyLoader" id="CircuitPythonDevice.__startTeensyLoader" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__startTeensyLoader" />
-      <keyword name="CircuitPythonDevice.addDeviceMenuEntries" id="CircuitPythonDevice.addDeviceMenuEntries" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.addDeviceMenuEntries" />
-      <keyword name="CircuitPythonDevice.canRunScript" id="CircuitPythonDevice.canRunScript" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.canRunScript" />
-      <keyword name="CircuitPythonDevice.canStartFileManager" id="CircuitPythonDevice.canStartFileManager" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.canStartFileManager" />
-      <keyword name="CircuitPythonDevice.canStartPlotter" id="CircuitPythonDevice.canStartPlotter" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.canStartPlotter" />
-      <keyword name="CircuitPythonDevice.canStartRepl" id="CircuitPythonDevice.canStartRepl" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.canStartRepl" />
-      <keyword name="CircuitPythonDevice.deviceName" id="CircuitPythonDevice.deviceName" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.deviceName" />
-      <keyword name="CircuitPythonDevice.forceInterrupt" id="CircuitPythonDevice.forceInterrupt" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.forceInterrupt" />
-      <keyword name="CircuitPythonDevice.getDocumentationUrl" id="CircuitPythonDevice.getDocumentationUrl" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.getDocumentationUrl" />
-      <keyword name="CircuitPythonDevice.getDownloadMenuEntries" id="CircuitPythonDevice.getDownloadMenuEntries" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.getDownloadMenuEntries" />
-      <keyword name="CircuitPythonDevice.getWorkspace" id="CircuitPythonDevice.getWorkspace" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.getWorkspace" />
-      <keyword name="CircuitPythonDevice.hasFlashMenuEntry" id="CircuitPythonDevice.hasFlashMenuEntry" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.hasFlashMenuEntry" />
-      <keyword name="CircuitPythonDevice.runScript" id="CircuitPythonDevice.runScript" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.runScript" />
-      <keyword name="CircuitPythonDevice.setButtons" id="CircuitPythonDevice.setButtons" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.setButtons" />
-      <keyword name="CircuitPythonDevice.supportsLocalFileAccess" id="CircuitPythonDevice.supportsLocalFileAccess" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.supportsLocalFileAccess" />
-      <keyword name="CircuitPythonDevices (Module)" id="CircuitPythonDevices (Module)" ref="eric7.MicroPython.CircuitPythonDevices.html" />
-      <keyword name="CircuitPythonUpdater (Package)" id="CircuitPythonUpdater (Package)" ref="index-eric7.MicroPython.CircuitPythonUpdater.html" />
-      <keyword name="CircuitPythonUpdaterInterface" id="CircuitPythonUpdaterInterface" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface" />
-      <keyword name="CircuitPythonUpdaterInterface (Constructor)" id="CircuitPythonUpdaterInterface (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__init__" />
-      <keyword name="CircuitPythonUpdaterInterface (Module)" id="CircuitPythonUpdaterInterface (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html" />
-      <keyword name="CircuitPythonUpdaterInterface.__aboutCircup" id="CircuitPythonUpdaterInterface.__aboutCircup" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__aboutCircup" />
-      <keyword name="CircuitPythonUpdaterInterface.__addBundle" id="CircuitPythonUpdaterInterface.__addBundle" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__addBundle" />
-      <keyword name="CircuitPythonUpdaterInterface.__doUpdateModules" id="CircuitPythonUpdaterInterface.__doUpdateModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__doUpdateModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__generateRequirements" id="CircuitPythonUpdaterInterface.__generateRequirements" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__generateRequirements" />
-      <keyword name="CircuitPythonUpdaterInterface.__installFromAvailable" id="CircuitPythonUpdaterInterface.__installFromAvailable" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installFromAvailable" />
-      <keyword name="CircuitPythonUpdaterInterface.__installFromCode" id="CircuitPythonUpdaterInterface.__installFromCode" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installFromCode" />
-      <keyword name="CircuitPythonUpdaterInterface.__installModules" id="CircuitPythonUpdaterInterface.__installModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__installRequirements" id="CircuitPythonUpdaterInterface.__installRequirements" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installRequirements" />
-      <keyword name="CircuitPythonUpdaterInterface.__listOutdatedModules" id="CircuitPythonUpdaterInterface.__listOutdatedModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__listOutdatedModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__removeBundle" id="CircuitPythonUpdaterInterface.__removeBundle" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__removeBundle" />
-      <keyword name="CircuitPythonUpdaterInterface.__showAvailableModules" id="CircuitPythonUpdaterInterface.__showAvailableModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showAvailableModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__showBundles" id="CircuitPythonUpdaterInterface.__showBundles" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showBundles" />
-      <keyword name="CircuitPythonUpdaterInterface.__showBundlesModules" id="CircuitPythonUpdaterInterface.__showBundlesModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showBundlesModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__showInstalledModules" id="CircuitPythonUpdaterInterface.__showInstalledModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showInstalledModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__uninstallModules" id="CircuitPythonUpdaterInterface.__uninstallModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__uninstallModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__updateAllModules" id="CircuitPythonUpdaterInterface.__updateAllModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__updateAllModules" />
-      <keyword name="CircuitPythonUpdaterInterface.__updateModules" id="CircuitPythonUpdaterInterface.__updateModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__updateModules" />
-      <keyword name="CircuitPythonUpdaterInterface.installCircup" id="CircuitPythonUpdaterInterface.installCircup" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.installCircup" />
-      <keyword name="CircuitPythonUpdaterInterface.populateMenu" id="CircuitPythonUpdaterInterface.populateMenu" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.populateMenu" />
-      <keyword name="CircupFunctions (Module)" id="CircupFunctions (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html" />
+      <keyword name="CircuitPythonDevice" id="CircuitPythonDevice" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice" />
+      <keyword name="CircuitPythonDevice (Constructor)" id="CircuitPythonDevice (Constructor)" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__init__" />
+      <keyword name="CircuitPythonDevice.__aboutToShowLibraryMenu" id="CircuitPythonDevice.__aboutToShowLibraryMenu" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__aboutToShowLibraryMenu" />
+      <keyword name="CircuitPythonDevice.__cpyVersionResponse" id="CircuitPythonDevice.__cpyVersionResponse" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__cpyVersionResponse" />
+      <keyword name="CircuitPythonDevice.__createCPyMenu" id="CircuitPythonDevice.__createCPyMenu" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__createCPyMenu" />
+      <keyword name="CircuitPythonDevice.__deviceVolumeMounted" id="CircuitPythonDevice.__deviceVolumeMounted" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__deviceVolumeMounted" />
+      <keyword name="CircuitPythonDevice.__findDeviceDirectories" id="CircuitPythonDevice.__findDeviceDirectories" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__findDeviceDirectories" />
+      <keyword name="CircuitPythonDevice.__findWorkspace" id="CircuitPythonDevice.__findWorkspace" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__findWorkspace" />
+      <keyword name="CircuitPythonDevice.__flashCircuitPython" id="CircuitPythonDevice.__flashCircuitPython" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__flashCircuitPython" />
+      <keyword name="CircuitPythonDevice.__installLibraryFiles" id="CircuitPythonDevice.__installLibraryFiles" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__installLibraryFiles" />
+      <keyword name="CircuitPythonDevice.__showCircuitPythonVersions" id="CircuitPythonDevice.__showCircuitPythonVersions" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__showCircuitPythonVersions" />
+      <keyword name="CircuitPythonDevice.__showTeensyFlashInstructions" id="CircuitPythonDevice.__showTeensyFlashInstructions" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__showTeensyFlashInstructions" />
+      <keyword name="CircuitPythonDevice.__startTeensyLoader" id="CircuitPythonDevice.__startTeensyLoader" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.__startTeensyLoader" />
+      <keyword name="CircuitPythonDevice.addDeviceMenuEntries" id="CircuitPythonDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.addDeviceMenuEntries" />
+      <keyword name="CircuitPythonDevice.canRunScript" id="CircuitPythonDevice.canRunScript" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.canRunScript" />
+      <keyword name="CircuitPythonDevice.canStartFileManager" id="CircuitPythonDevice.canStartFileManager" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.canStartFileManager" />
+      <keyword name="CircuitPythonDevice.canStartPlotter" id="CircuitPythonDevice.canStartPlotter" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.canStartPlotter" />
+      <keyword name="CircuitPythonDevice.canStartRepl" id="CircuitPythonDevice.canStartRepl" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.canStartRepl" />
+      <keyword name="CircuitPythonDevice.deviceName" id="CircuitPythonDevice.deviceName" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.deviceName" />
+      <keyword name="CircuitPythonDevice.forceInterrupt" id="CircuitPythonDevice.forceInterrupt" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.forceInterrupt" />
+      <keyword name="CircuitPythonDevice.getDocumentationUrl" id="CircuitPythonDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.getDocumentationUrl" />
+      <keyword name="CircuitPythonDevice.getDownloadMenuEntries" id="CircuitPythonDevice.getDownloadMenuEntries" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.getDownloadMenuEntries" />
+      <keyword name="CircuitPythonDevice.getWorkspace" id="CircuitPythonDevice.getWorkspace" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.getWorkspace" />
+      <keyword name="CircuitPythonDevice.hasFlashMenuEntry" id="CircuitPythonDevice.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.hasFlashMenuEntry" />
+      <keyword name="CircuitPythonDevice.runScript" id="CircuitPythonDevice.runScript" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.runScript" />
+      <keyword name="CircuitPythonDevice.setButtons" id="CircuitPythonDevice.setButtons" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.setButtons" />
+      <keyword name="CircuitPythonDevice.supportsLocalFileAccess" id="CircuitPythonDevice.supportsLocalFileAccess" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#CircuitPythonDevice.supportsLocalFileAccess" />
+      <keyword name="CircuitPythonDevices (Module)" id="CircuitPythonDevices (Module)" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html" />
+      <keyword name="CircuitPythonUpdater (Package)" id="CircuitPythonUpdater (Package)" ref="index-eric7.MicroPython.Devices.CircuitPythonUpdater.html" />
+      <keyword name="CircuitPythonUpdaterInterface" id="CircuitPythonUpdaterInterface" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface" />
+      <keyword name="CircuitPythonUpdaterInterface (Constructor)" id="CircuitPythonUpdaterInterface (Constructor)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__init__" />
+      <keyword name="CircuitPythonUpdaterInterface (Module)" id="CircuitPythonUpdaterInterface (Module)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html" />
+      <keyword name="CircuitPythonUpdaterInterface.__aboutCircup" id="CircuitPythonUpdaterInterface.__aboutCircup" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__aboutCircup" />
+      <keyword name="CircuitPythonUpdaterInterface.__addBundle" id="CircuitPythonUpdaterInterface.__addBundle" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__addBundle" />
+      <keyword name="CircuitPythonUpdaterInterface.__doUpdateModules" id="CircuitPythonUpdaterInterface.__doUpdateModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__doUpdateModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__generateRequirements" id="CircuitPythonUpdaterInterface.__generateRequirements" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__generateRequirements" />
+      <keyword name="CircuitPythonUpdaterInterface.__installFromAvailable" id="CircuitPythonUpdaterInterface.__installFromAvailable" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installFromAvailable" />
+      <keyword name="CircuitPythonUpdaterInterface.__installFromCode" id="CircuitPythonUpdaterInterface.__installFromCode" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installFromCode" />
+      <keyword name="CircuitPythonUpdaterInterface.__installModules" id="CircuitPythonUpdaterInterface.__installModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__installRequirements" id="CircuitPythonUpdaterInterface.__installRequirements" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installRequirements" />
+      <keyword name="CircuitPythonUpdaterInterface.__listOutdatedModules" id="CircuitPythonUpdaterInterface.__listOutdatedModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__listOutdatedModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__removeBundle" id="CircuitPythonUpdaterInterface.__removeBundle" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__removeBundle" />
+      <keyword name="CircuitPythonUpdaterInterface.__showAvailableModules" id="CircuitPythonUpdaterInterface.__showAvailableModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showAvailableModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__showBundles" id="CircuitPythonUpdaterInterface.__showBundles" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showBundles" />
+      <keyword name="CircuitPythonUpdaterInterface.__showBundlesModules" id="CircuitPythonUpdaterInterface.__showBundlesModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showBundlesModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__showInstalledModules" id="CircuitPythonUpdaterInterface.__showInstalledModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showInstalledModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__uninstallModules" id="CircuitPythonUpdaterInterface.__uninstallModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__uninstallModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__updateAllModules" id="CircuitPythonUpdaterInterface.__updateAllModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__updateAllModules" />
+      <keyword name="CircuitPythonUpdaterInterface.__updateModules" id="CircuitPythonUpdaterInterface.__updateModules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__updateModules" />
+      <keyword name="CircuitPythonUpdaterInterface.installCircup" id="CircuitPythonUpdaterInterface.installCircup" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.installCircup" />
+      <keyword name="CircuitPythonUpdaterInterface.populateMenu" id="CircuitPythonUpdaterInterface.populateMenu" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.populateMenu" />
+      <keyword name="CircupFunctions (Module)" id="CircupFunctions (Module)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html" />
       <keyword name="Class" id="Class" ref="eric7.Utilities.ClassBrowsers.ClbrBaseClasses.html#Class" />
       <keyword name="Class" id="Class" ref="eric7.Utilities.ClassBrowsers.pyclbr.html#Class" />
       <keyword name="Class" id="Class" ref="eric7.Utilities.ClassBrowsers.rbclbr.html#Class" />
@@ -3965,6 +4001,8 @@
       <keyword name="DeleteFilesConfirmationDialog (Module)" id="DeleteFilesConfirmationDialog (Module)" ref="eric7.UI.DeleteFilesConfirmationDialog.html" />
       <keyword name="DeleteFilesConfirmationDialog.on_buttonBox_clicked" id="DeleteFilesConfirmationDialog.on_buttonBox_clicked" ref="eric7.UI.DeleteFilesConfirmationDialog.html#DeleteFilesConfirmationDialog.on_buttonBox_clicked" />
       <keyword name="DesktopUtilities (Module)" id="DesktopUtilities (Module)" ref="eric7.SystemUtilities.DesktopUtilities.html" />
+      <keyword name="DeviceBase (Module)" id="DeviceBase (Module)" ref="eric7.MicroPython.Devices.DeviceBase.html" />
+      <keyword name="Devices (Package)" id="Devices (Package)" ref="index-eric7.MicroPython.Devices.html" />
       <keyword name="DictResolver" id="DictResolver" ref="eric7.DebugClients.Python.DebugVariables.html#DictResolver" />
       <keyword name="DictResolver.getVariableList" id="DictResolver.getVariableList" ref="eric7.DebugClients.Python.DebugVariables.html#DictResolver.getVariableList" />
       <keyword name="DictResolver.keyToStr" id="DictResolver.keyToStr" ref="eric7.DebugClients.Python.DebugVariables.html#DictResolver.keyToStr" />
@@ -4370,7 +4408,6 @@
       <keyword name="Editor.__setAutoCompletion" id="Editor.__setAutoCompletion" ref="eric7.QScintilla.Editor.html#Editor.__setAutoCompletion" />
       <keyword name="Editor.__setCallTips" id="Editor.__setCallTips" ref="eric7.QScintilla.Editor.html#Editor.__setCallTips" />
       <keyword name="Editor.__setEolMode" id="Editor.__setEolMode" ref="eric7.QScintilla.Editor.html#Editor.__setEolMode" />
-      <keyword name="Editor.__setFileName" id="Editor.__setFileName" ref="eric7.QScintilla.Editor.html#Editor.__setFileName" />
       <keyword name="Editor.__setLineMarkerColours" id="Editor.__setLineMarkerColours" ref="eric7.QScintilla.Editor.html#Editor.__setLineMarkerColours" />
       <keyword name="Editor.__setMarginsDisplay" id="Editor.__setMarginsDisplay" ref="eric7.QScintilla.Editor.html#Editor.__setMarginsDisplay" />
       <keyword name="Editor.__setSpelling" id="Editor.__setSpelling" ref="eric7.QScintilla.Editor.html#Editor.__setSpelling" />
@@ -4430,11 +4467,13 @@
       <keyword name="Editor.cancelSharedEdit" id="Editor.cancelSharedEdit" ref="eric7.QScintilla.Editor.html#Editor.cancelSharedEdit" />
       <keyword name="Editor.changeEvent" id="Editor.changeEvent" ref="eric7.QScintilla.Editor.html#Editor.changeEvent" />
       <keyword name="Editor.checkDirty" id="Editor.checkDirty" ref="eric7.QScintilla.Editor.html#Editor.checkDirty" />
+      <keyword name="Editor.checkReadOnly" id="Editor.checkReadOnly" ref="eric7.QScintilla.Editor.html#Editor.checkReadOnly" />
       <keyword name="Editor.checkSpelling" id="Editor.checkSpelling" ref="eric7.QScintilla.Editor.html#Editor.checkSpelling" />
       <keyword name="Editor.checkSyntax" id="Editor.checkSyntax" ref="eric7.QScintilla.Editor.html#Editor.checkSyntax" />
       <keyword name="Editor.clearAllHighlights" id="Editor.clearAllHighlights" ref="eric7.QScintilla.Editor.html#Editor.clearAllHighlights" />
       <keyword name="Editor.clearBookmarks" id="Editor.clearBookmarks" ref="eric7.QScintilla.Editor.html#Editor.clearBookmarks" />
       <keyword name="Editor.clearBreakpoint" id="Editor.clearBreakpoint" ref="eric7.QScintilla.Editor.html#Editor.clearBreakpoint" />
+      <keyword name="Editor.clearChangeMarkers" id="Editor.clearChangeMarkers" ref="eric7.QScintilla.Editor.html#Editor.clearChangeMarkers" />
       <keyword name="Editor.clearFlakesWarnings" id="Editor.clearFlakesWarnings" ref="eric7.QScintilla.Editor.html#Editor.clearFlakesWarnings" />
       <keyword name="Editor.clearHighlight" id="Editor.clearHighlight" ref="eric7.QScintilla.Editor.html#Editor.clearHighlight" />
       <keyword name="Editor.clearSearchIndicators" id="Editor.clearSearchIndicators" ref="eric7.QScintilla.Editor.html#Editor.clearSearchIndicators" />
@@ -4529,6 +4568,7 @@
       <keyword name="Editor.isCythonFile" id="Editor.isCythonFile" ref="eric7.QScintilla.Editor.html#Editor.isCythonFile" />
       <keyword name="Editor.isJavascriptFile" id="Editor.isJavascriptFile" ref="eric7.QScintilla.Editor.html#Editor.isJavascriptFile" />
       <keyword name="Editor.isLastEditPositionAvailable" id="Editor.isLastEditPositionAvailable" ref="eric7.QScintilla.Editor.html#Editor.isLastEditPositionAvailable" />
+      <keyword name="Editor.isLocalFile" id="Editor.isLocalFile" ref="eric7.QScintilla.Editor.html#Editor.isLocalFile" />
       <keyword name="Editor.isMicroPythonFile" id="Editor.isMicroPythonFile" ref="eric7.QScintilla.Editor.html#Editor.isMicroPythonFile" />
       <keyword name="Editor.isPy3File" id="Editor.isPy3File" ref="eric7.QScintilla.Editor.html#Editor.isPy3File" />
       <keyword name="Editor.isPyFile" id="Editor.isPyFile" ref="eric7.QScintilla.Editor.html#Editor.isPyFile" />
@@ -4590,6 +4630,7 @@
       <keyword name="Editor.sendSharedEdit" id="Editor.sendSharedEdit" ref="eric7.QScintilla.Editor.html#Editor.sendSharedEdit" />
       <keyword name="Editor.setAutoCompletionEnabled" id="Editor.setAutoCompletionEnabled" ref="eric7.QScintilla.Editor.html#Editor.setAutoCompletionEnabled" />
       <keyword name="Editor.setAutoSpellChecking" id="Editor.setAutoSpellChecking" ref="eric7.QScintilla.Editor.html#Editor.setAutoSpellChecking" />
+      <keyword name="Editor.setFileName" id="Editor.setFileName" ref="eric7.QScintilla.Editor.html#Editor.setFileName" />
       <keyword name="Editor.setHighlight" id="Editor.setHighlight" ref="eric7.QScintilla.Editor.html#Editor.setHighlight" />
       <keyword name="Editor.setLanguage" id="Editor.setLanguage" ref="eric7.QScintilla.Editor.html#Editor.setLanguage" />
       <keyword name="Editor.setMonospaced" id="Editor.setMonospaced" ref="eric7.QScintilla.Editor.html#Editor.setMonospaced" />
@@ -6038,50 +6079,51 @@
       <keyword name="ErrorLogDialog.on_deleteButton_clicked" id="ErrorLogDialog.on_deleteButton_clicked" ref="eric7.UI.ErrorLogDialog.html#ErrorLogDialog.on_deleteButton_clicked" />
       <keyword name="ErrorLogDialog.on_emailButton_clicked" id="ErrorLogDialog.on_emailButton_clicked" ref="eric7.UI.ErrorLogDialog.html#ErrorLogDialog.on_emailButton_clicked" />
       <keyword name="ErrorLogDialog.on_keepButton_clicked" id="ErrorLogDialog.on_keepButton_clicked" ref="eric7.UI.ErrorLogDialog.html#ErrorLogDialog.on_keepButton_clicked" />
-      <keyword name="EspBackupRestoreFirmwareDialog" id="EspBackupRestoreFirmwareDialog" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog" />
-      <keyword name="EspBackupRestoreFirmwareDialog (Constructor)" id="EspBackupRestoreFirmwareDialog (Constructor)" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.__init__" />
-      <keyword name="EspBackupRestoreFirmwareDialog (Module)" id="EspBackupRestoreFirmwareDialog (Module)" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html" />
-      <keyword name="EspBackupRestoreFirmwareDialog.__updateOkButton" id="EspBackupRestoreFirmwareDialog.__updateOkButton" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.__updateOkButton" />
-      <keyword name="EspBackupRestoreFirmwareDialog.getData" id="EspBackupRestoreFirmwareDialog.getData" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.getData" />
-      <keyword name="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" id="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" />
-      <keyword name="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" id="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" />
-      <keyword name="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" id="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" ref="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" />
-      <keyword name="EspDevice" id="EspDevice" ref="eric7.MicroPython.EspDevices.html#EspDevice" />
-      <keyword name="EspDevice (Constructor)" id="EspDevice (Constructor)" ref="eric7.MicroPython.EspDevices.html#EspDevice.__init__" />
-      <keyword name="EspDevice.__backupFlash" id="EspDevice.__backupFlash" ref="eric7.MicroPython.EspDevices.html#EspDevice.__backupFlash" />
-      <keyword name="EspDevice.__createEsp32Submenu" id="EspDevice.__createEsp32Submenu" ref="eric7.MicroPython.EspDevices.html#EspDevice.__createEsp32Submenu" />
-      <keyword name="EspDevice.__eraseFlash" id="EspDevice.__eraseFlash" ref="eric7.MicroPython.EspDevices.html#EspDevice.__eraseFlash" />
-      <keyword name="EspDevice.__firmwareVersionResponse" id="EspDevice.__firmwareVersionResponse" ref="eric7.MicroPython.EspDevices.html#EspDevice.__firmwareVersionResponse" />
-      <keyword name="EspDevice.__flashAddons" id="EspDevice.__flashAddons" ref="eric7.MicroPython.EspDevices.html#EspDevice.__flashAddons" />
-      <keyword name="EspDevice.__flashMicroPython" id="EspDevice.__flashMicroPython" ref="eric7.MicroPython.EspDevices.html#EspDevice.__flashMicroPython" />
-      <keyword name="EspDevice.__installEspTool" id="EspDevice.__installEspTool" ref="eric7.MicroPython.EspDevices.html#EspDevice.__installEspTool" />
-      <keyword name="EspDevice.__resetDevice" id="EspDevice.__resetDevice" ref="eric7.MicroPython.EspDevices.html#EspDevice.__resetDevice" />
-      <keyword name="EspDevice.__restoreFlash" id="EspDevice.__restoreFlash" ref="eric7.MicroPython.EspDevices.html#EspDevice.__restoreFlash" />
-      <keyword name="EspDevice.__showChipID" id="EspDevice.__showChipID" ref="eric7.MicroPython.EspDevices.html#EspDevice.__showChipID" />
-      <keyword name="EspDevice.__showFirmwareVersions" id="EspDevice.__showFirmwareVersions" ref="eric7.MicroPython.EspDevices.html#EspDevice.__showFirmwareVersions" />
-      <keyword name="EspDevice.__showFlashID" id="EspDevice.__showFlashID" ref="eric7.MicroPython.EspDevices.html#EspDevice.__showFlashID" />
-      <keyword name="EspDevice.__showMACAddress" id="EspDevice.__showMACAddress" ref="eric7.MicroPython.EspDevices.html#EspDevice.__showMACAddress" />
-      <keyword name="EspDevice.addDeviceMenuEntries" id="EspDevice.addDeviceMenuEntries" ref="eric7.MicroPython.EspDevices.html#EspDevice.addDeviceMenuEntries" />
-      <keyword name="EspDevice.canRunScript" id="EspDevice.canRunScript" ref="eric7.MicroPython.EspDevices.html#EspDevice.canRunScript" />
-      <keyword name="EspDevice.canStartFileManager" id="EspDevice.canStartFileManager" ref="eric7.MicroPython.EspDevices.html#EspDevice.canStartFileManager" />
-      <keyword name="EspDevice.canStartPlotter" id="EspDevice.canStartPlotter" ref="eric7.MicroPython.EspDevices.html#EspDevice.canStartPlotter" />
-      <keyword name="EspDevice.canStartRepl" id="EspDevice.canStartRepl" ref="eric7.MicroPython.EspDevices.html#EspDevice.canStartRepl" />
-      <keyword name="EspDevice.deviceName" id="EspDevice.deviceName" ref="eric7.MicroPython.EspDevices.html#EspDevice.deviceName" />
-      <keyword name="EspDevice.forceInterrupt" id="EspDevice.forceInterrupt" ref="eric7.MicroPython.EspDevices.html#EspDevice.forceInterrupt" />
-      <keyword name="EspDevice.getDocumentationUrl" id="EspDevice.getDocumentationUrl" ref="eric7.MicroPython.EspDevices.html#EspDevice.getDocumentationUrl" />
-      <keyword name="EspDevice.getFirmwareUrl" id="EspDevice.getFirmwareUrl" ref="eric7.MicroPython.EspDevices.html#EspDevice.getFirmwareUrl" />
-      <keyword name="EspDevice.hasFlashMenuEntry" id="EspDevice.hasFlashMenuEntry" ref="eric7.MicroPython.EspDevices.html#EspDevice.hasFlashMenuEntry" />
-      <keyword name="EspDevice.runScript" id="EspDevice.runScript" ref="eric7.MicroPython.EspDevices.html#EspDevice.runScript" />
-      <keyword name="EspDevice.setButtons" id="EspDevice.setButtons" ref="eric7.MicroPython.EspDevices.html#EspDevice.setButtons" />
-      <keyword name="EspDevices (Module)" id="EspDevices (Module)" ref="eric7.MicroPython.EspDevices.html" />
-      <keyword name="EspFirmwareSelectionDialog" id="EspFirmwareSelectionDialog" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog" />
-      <keyword name="EspFirmwareSelectionDialog (Constructor)" id="EspFirmwareSelectionDialog (Constructor)" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.__init__" />
-      <keyword name="EspFirmwareSelectionDialog (Module)" id="EspFirmwareSelectionDialog (Module)" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html" />
-      <keyword name="EspFirmwareSelectionDialog.__updateOkButton" id="EspFirmwareSelectionDialog.__updateOkButton" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.__updateOkButton" />
-      <keyword name="EspFirmwareSelectionDialog.getData" id="EspFirmwareSelectionDialog.getData" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.getData" />
-      <keyword name="EspFirmwareSelectionDialog.on_addressEdit_textChanged" id="EspFirmwareSelectionDialog.on_addressEdit_textChanged" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.on_addressEdit_textChanged" />
-      <keyword name="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" id="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" />
-      <keyword name="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" id="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" ref="eric7.MicroPython.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" />
+      <keyword name="EspBackupRestoreFirmwareDialog" id="EspBackupRestoreFirmwareDialog" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog" />
+      <keyword name="EspBackupRestoreFirmwareDialog (Constructor)" id="EspBackupRestoreFirmwareDialog (Constructor)" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.__init__" />
+      <keyword name="EspBackupRestoreFirmwareDialog (Module)" id="EspBackupRestoreFirmwareDialog (Module)" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html" />
+      <keyword name="EspBackupRestoreFirmwareDialog.__updateOkButton" id="EspBackupRestoreFirmwareDialog.__updateOkButton" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.__updateOkButton" />
+      <keyword name="EspBackupRestoreFirmwareDialog.getData" id="EspBackupRestoreFirmwareDialog.getData" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.getData" />
+      <keyword name="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" id="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" />
+      <keyword name="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" id="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" />
+      <keyword name="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" id="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" ref="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html#EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" />
+      <keyword name="EspDevice" id="EspDevice" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice" />
+      <keyword name="EspDevice (Constructor)" id="EspDevice (Constructor)" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__init__" />
+      <keyword name="EspDevice.__backupFlash" id="EspDevice.__backupFlash" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__backupFlash" />
+      <keyword name="EspDevice.__createEsp32Submenu" id="EspDevice.__createEsp32Submenu" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__createEsp32Submenu" />
+      <keyword name="EspDevice.__eraseFlash" id="EspDevice.__eraseFlash" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__eraseFlash" />
+      <keyword name="EspDevice.__firmwareVersionResponse" id="EspDevice.__firmwareVersionResponse" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__firmwareVersionResponse" />
+      <keyword name="EspDevice.__flashAddons" id="EspDevice.__flashAddons" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__flashAddons" />
+      <keyword name="EspDevice.__flashMicroPython" id="EspDevice.__flashMicroPython" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__flashMicroPython" />
+      <keyword name="EspDevice.__installEspTool" id="EspDevice.__installEspTool" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__installEspTool" />
+      <keyword name="EspDevice.__resetDevice" id="EspDevice.__resetDevice" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__resetDevice" />
+      <keyword name="EspDevice.__restoreFlash" id="EspDevice.__restoreFlash" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__restoreFlash" />
+      <keyword name="EspDevice.__showChipID" id="EspDevice.__showChipID" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__showChipID" />
+      <keyword name="EspDevice.__showFirmwareVersions" id="EspDevice.__showFirmwareVersions" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__showFirmwareVersions" />
+      <keyword name="EspDevice.__showFlashID" id="EspDevice.__showFlashID" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__showFlashID" />
+      <keyword name="EspDevice.__showMACAddress" id="EspDevice.__showMACAddress" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.__showMACAddress" />
+      <keyword name="EspDevice.addDeviceMenuEntries" id="EspDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.addDeviceMenuEntries" />
+      <keyword name="EspDevice.canRunScript" id="EspDevice.canRunScript" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.canRunScript" />
+      <keyword name="EspDevice.canStartFileManager" id="EspDevice.canStartFileManager" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.canStartFileManager" />
+      <keyword name="EspDevice.canStartPlotter" id="EspDevice.canStartPlotter" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.canStartPlotter" />
+      <keyword name="EspDevice.canStartRepl" id="EspDevice.canStartRepl" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.canStartRepl" />
+      <keyword name="EspDevice.deviceName" id="EspDevice.deviceName" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.deviceName" />
+      <keyword name="EspDevice.forceInterrupt" id="EspDevice.forceInterrupt" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.forceInterrupt" />
+      <keyword name="EspDevice.getDocumentationUrl" id="EspDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.getDocumentationUrl" />
+      <keyword name="EspDevice.getFirmwareUrl" id="EspDevice.getFirmwareUrl" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.getFirmwareUrl" />
+      <keyword name="EspDevice.hasFlashMenuEntry" id="EspDevice.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.hasFlashMenuEntry" />
+      <keyword name="EspDevice.runScript" id="EspDevice.runScript" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.runScript" />
+      <keyword name="EspDevice.setButtons" id="EspDevice.setButtons" ref="eric7.MicroPython.Devices.EspDevices.html#EspDevice.setButtons" />
+      <keyword name="EspDevices (Module)" id="EspDevices (Module)" ref="eric7.MicroPython.Devices.EspDevices.html" />
+      <keyword name="EspDialogs (Package)" id="EspDialogs (Package)" ref="index-eric7.MicroPython.Devices.EspDialogs.html" />
+      <keyword name="EspFirmwareSelectionDialog" id="EspFirmwareSelectionDialog" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog" />
+      <keyword name="EspFirmwareSelectionDialog (Constructor)" id="EspFirmwareSelectionDialog (Constructor)" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.__init__" />
+      <keyword name="EspFirmwareSelectionDialog (Module)" id="EspFirmwareSelectionDialog (Module)" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html" />
+      <keyword name="EspFirmwareSelectionDialog.__updateOkButton" id="EspFirmwareSelectionDialog.__updateOkButton" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.__updateOkButton" />
+      <keyword name="EspFirmwareSelectionDialog.getData" id="EspFirmwareSelectionDialog.getData" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.getData" />
+      <keyword name="EspFirmwareSelectionDialog.on_addressEdit_textChanged" id="EspFirmwareSelectionDialog.on_addressEdit_textChanged" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.on_addressEdit_textChanged" />
+      <keyword name="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" id="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" />
+      <keyword name="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" id="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" ref="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html#EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" />
       <keyword name="ExceptionLogger" id="ExceptionLogger" ref="eric7.Debugger.ExceptionLogger.html#ExceptionLogger" />
       <keyword name="ExceptionLogger (Constructor)" id="ExceptionLogger (Constructor)" ref="eric7.Debugger.ExceptionLogger.html#ExceptionLogger.__init__" />
       <keyword name="ExceptionLogger (Module)" id="ExceptionLogger (Module)" ref="eric7.Debugger.ExceptionLogger.html" />
@@ -6422,20 +6464,20 @@
       <keyword name="FunctionVisitor" id="FunctionVisitor" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Annotations.AnnotationsFunctionVisitor.html#FunctionVisitor" />
       <keyword name="FunctionVisitor (Constructor)" id="FunctionVisitor (Constructor)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Annotations.AnnotationsFunctionVisitor.html#FunctionVisitor.__init__" />
       <keyword name="FunctionVisitor.switchContext" id="FunctionVisitor.switchContext" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Annotations.AnnotationsFunctionVisitor.html#FunctionVisitor.switchContext" />
-      <keyword name="GenericMicroPythonDevice" id="GenericMicroPythonDevice" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice" />
-      <keyword name="GenericMicroPythonDevice (Constructor)" id="GenericMicroPythonDevice (Constructor)" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.__init__" />
-      <keyword name="GenericMicroPythonDevice.__deviceVolumeMounted" id="GenericMicroPythonDevice.__deviceVolumeMounted" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.__deviceVolumeMounted" />
-      <keyword name="GenericMicroPythonDevice.__findWorkspace" id="GenericMicroPythonDevice.__findWorkspace" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.__findWorkspace" />
-      <keyword name="GenericMicroPythonDevice.canRunScript" id="GenericMicroPythonDevice.canRunScript" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canRunScript" />
-      <keyword name="GenericMicroPythonDevice.canStartFileManager" id="GenericMicroPythonDevice.canStartFileManager" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canStartFileManager" />
-      <keyword name="GenericMicroPythonDevice.canStartPlotter" id="GenericMicroPythonDevice.canStartPlotter" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canStartPlotter" />
-      <keyword name="GenericMicroPythonDevice.canStartRepl" id="GenericMicroPythonDevice.canStartRepl" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canStartRepl" />
-      <keyword name="GenericMicroPythonDevice.deviceName" id="GenericMicroPythonDevice.deviceName" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.deviceName" />
-      <keyword name="GenericMicroPythonDevice.getWorkspace" id="GenericMicroPythonDevice.getWorkspace" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.getWorkspace" />
-      <keyword name="GenericMicroPythonDevice.runScript" id="GenericMicroPythonDevice.runScript" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.runScript" />
-      <keyword name="GenericMicroPythonDevice.setButtons" id="GenericMicroPythonDevice.setButtons" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.setButtons" />
-      <keyword name="GenericMicroPythonDevice.supportsLocalFileAccess" id="GenericMicroPythonDevice.supportsLocalFileAccess" ref="eric7.MicroPython.GenericMicroPythonDevices.html#GenericMicroPythonDevice.supportsLocalFileAccess" />
-      <keyword name="GenericMicroPythonDevices (Module)" id="GenericMicroPythonDevices (Module)" ref="eric7.MicroPython.GenericMicroPythonDevices.html" />
+      <keyword name="GenericMicroPythonDevice" id="GenericMicroPythonDevice" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice" />
+      <keyword name="GenericMicroPythonDevice (Constructor)" id="GenericMicroPythonDevice (Constructor)" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.__init__" />
+      <keyword name="GenericMicroPythonDevice.__deviceVolumeMounted" id="GenericMicroPythonDevice.__deviceVolumeMounted" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.__deviceVolumeMounted" />
+      <keyword name="GenericMicroPythonDevice.__findWorkspace" id="GenericMicroPythonDevice.__findWorkspace" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.__findWorkspace" />
+      <keyword name="GenericMicroPythonDevice.canRunScript" id="GenericMicroPythonDevice.canRunScript" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canRunScript" />
+      <keyword name="GenericMicroPythonDevice.canStartFileManager" id="GenericMicroPythonDevice.canStartFileManager" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canStartFileManager" />
+      <keyword name="GenericMicroPythonDevice.canStartPlotter" id="GenericMicroPythonDevice.canStartPlotter" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canStartPlotter" />
+      <keyword name="GenericMicroPythonDevice.canStartRepl" id="GenericMicroPythonDevice.canStartRepl" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.canStartRepl" />
+      <keyword name="GenericMicroPythonDevice.deviceName" id="GenericMicroPythonDevice.deviceName" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.deviceName" />
+      <keyword name="GenericMicroPythonDevice.getWorkspace" id="GenericMicroPythonDevice.getWorkspace" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.getWorkspace" />
+      <keyword name="GenericMicroPythonDevice.runScript" id="GenericMicroPythonDevice.runScript" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.runScript" />
+      <keyword name="GenericMicroPythonDevice.setButtons" id="GenericMicroPythonDevice.setButtons" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.setButtons" />
+      <keyword name="GenericMicroPythonDevice.supportsLocalFileAccess" id="GenericMicroPythonDevice.supportsLocalFileAccess" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#GenericMicroPythonDevice.supportsLocalFileAccess" />
+      <keyword name="GenericMicroPythonDevices (Module)" id="GenericMicroPythonDevices (Module)" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html" />
       <keyword name="GetMarkersPlugin" id="GetMarkersPlugin" ref="eric7.Testing.Interfaces.PytestRunner.html#GetMarkersPlugin" />
       <keyword name="GetMarkersPlugin (Constructor)" id="GetMarkersPlugin (Constructor)" ref="eric7.Testing.Interfaces.PytestRunner.html#GetMarkersPlugin.__init__" />
       <keyword name="GetMarkersPlugin.getMarkers" id="GetMarkersPlugin.getMarkers" ref="eric7.Testing.Interfaces.PytestRunner.html#GetMarkersPlugin.getMarkers" />
@@ -10509,6 +10551,7 @@
       <keyword name="MicroPythonCommandsInterface.fileSystemInfo" id="MicroPythonCommandsInterface.fileSystemInfo" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.fileSystemInfo" />
       <keyword name="MicroPythonCommandsInterface.get" id="MicroPythonCommandsInterface.get" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.get" />
       <keyword name="MicroPythonCommandsInterface.getBoardInformation" id="MicroPythonCommandsInterface.getBoardInformation" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.getBoardInformation" />
+      <keyword name="MicroPythonCommandsInterface.getData" id="MicroPythonCommandsInterface.getData" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.getData" />
       <keyword name="MicroPythonCommandsInterface.getDeviceData" id="MicroPythonCommandsInterface.getDeviceData" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.getDeviceData" />
       <keyword name="MicroPythonCommandsInterface.getModules" id="MicroPythonCommandsInterface.getModules" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.getModules" />
       <keyword name="MicroPythonCommandsInterface.getTime" id="MicroPythonCommandsInterface.getTime" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.getTime" />
@@ -10519,6 +10562,7 @@
       <keyword name="MicroPythonCommandsInterface.mkdir" id="MicroPythonCommandsInterface.mkdir" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.mkdir" />
       <keyword name="MicroPythonCommandsInterface.probeDevice" id="MicroPythonCommandsInterface.probeDevice" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.probeDevice" />
       <keyword name="MicroPythonCommandsInterface.put" id="MicroPythonCommandsInterface.put" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.put" />
+      <keyword name="MicroPythonCommandsInterface.putData" id="MicroPythonCommandsInterface.putData" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.putData" />
       <keyword name="MicroPythonCommandsInterface.pwd" id="MicroPythonCommandsInterface.pwd" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.pwd" />
       <keyword name="MicroPythonCommandsInterface.remainingTask" id="MicroPythonCommandsInterface.remainingTask" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.remainingTask" />
       <keyword name="MicroPythonCommandsInterface.rm" id="MicroPythonCommandsInterface.rm" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.rm" />
@@ -10526,38 +10570,6 @@
       <keyword name="MicroPythonCommandsInterface.rmrf" id="MicroPythonCommandsInterface.rmrf" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.rmrf" />
       <keyword name="MicroPythonCommandsInterface.syncTime" id="MicroPythonCommandsInterface.syncTime" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.syncTime" />
       <keyword name="MicroPythonCommandsInterface.write" id="MicroPythonCommandsInterface.write" ref="eric7.MicroPython.MicroPythonCommandsInterface.html#MicroPythonCommandsInterface.write" />
-      <keyword name="MicroPythonDevice" id="MicroPythonDevice" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice" />
-      <keyword name="MicroPythonDevice (Constructor)" id="MicroPythonDevice (Constructor)" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.__init__" />
-      <keyword name="MicroPythonDevice.addDeviceMenuEntries" id="MicroPythonDevice.addDeviceMenuEntries" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.addDeviceMenuEntries" />
-      <keyword name="MicroPythonDevice.canRunScript" id="MicroPythonDevice.canRunScript" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.canRunScript" />
-      <keyword name="MicroPythonDevice.canStartFileManager" id="MicroPythonDevice.canStartFileManager" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.canStartFileManager" />
-      <keyword name="MicroPythonDevice.canStartPlotter" id="MicroPythonDevice.canStartPlotter" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.canStartPlotter" />
-      <keyword name="MicroPythonDevice.canStartRepl" id="MicroPythonDevice.canStartRepl" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.canStartRepl" />
-      <keyword name="MicroPythonDevice.checkDeviceData" id="MicroPythonDevice.checkDeviceData" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.checkDeviceData" />
-      <keyword name="MicroPythonDevice.deviceName" id="MicroPythonDevice.deviceName" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.deviceName" />
-      <keyword name="MicroPythonDevice.downloadFirmware" id="MicroPythonDevice.downloadFirmware" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.downloadFirmware" />
-      <keyword name="MicroPythonDevice.forceInterrupt" id="MicroPythonDevice.forceInterrupt" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.forceInterrupt" />
-      <keyword name="MicroPythonDevice.getDeviceData" id="MicroPythonDevice.getDeviceData" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.getDeviceData" />
-      <keyword name="MicroPythonDevice.getDeviceType" id="MicroPythonDevice.getDeviceType" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.getDeviceType" />
-      <keyword name="MicroPythonDevice.getDocumentationUrl" id="MicroPythonDevice.getDocumentationUrl" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.getDocumentationUrl" />
-      <keyword name="MicroPythonDevice.getDownloadMenuEntries" id="MicroPythonDevice.getDownloadMenuEntries" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.getDownloadMenuEntries" />
-      <keyword name="MicroPythonDevice.getFirmwareUrl" id="MicroPythonDevice.getFirmwareUrl" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.getFirmwareUrl" />
-      <keyword name="MicroPythonDevice.getWorkspace" id="MicroPythonDevice.getWorkspace" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.getWorkspace" />
-      <keyword name="MicroPythonDevice.handleDataFlood" id="MicroPythonDevice.handleDataFlood" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.handleDataFlood" />
-      <keyword name="MicroPythonDevice.hasDocumentationUrl" id="MicroPythonDevice.hasDocumentationUrl" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.hasDocumentationUrl" />
-      <keyword name="MicroPythonDevice.hasFirmwareUrl" id="MicroPythonDevice.hasFirmwareUrl" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.hasFirmwareUrl" />
-      <keyword name="MicroPythonDevice.hasFlashMenuEntry" id="MicroPythonDevice.hasFlashMenuEntry" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.hasFlashMenuEntry" />
-      <keyword name="MicroPythonDevice.hasTimeCommands" id="MicroPythonDevice.hasTimeCommands" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.hasTimeCommands" />
-      <keyword name="MicroPythonDevice.runScript" id="MicroPythonDevice.runScript" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.runScript" />
-      <keyword name="MicroPythonDevice.selectDeviceDirectory" id="MicroPythonDevice.selectDeviceDirectory" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.selectDeviceDirectory" />
-      <keyword name="MicroPythonDevice.sendCommands" id="MicroPythonDevice.sendCommands" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.sendCommands" />
-      <keyword name="MicroPythonDevice.setButtons" id="MicroPythonDevice.setButtons" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.setButtons" />
-      <keyword name="MicroPythonDevice.setConnected" id="MicroPythonDevice.setConnected" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.setConnected" />
-      <keyword name="MicroPythonDevice.setFileManager" id="MicroPythonDevice.setFileManager" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.setFileManager" />
-      <keyword name="MicroPythonDevice.setPlotter" id="MicroPythonDevice.setPlotter" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.setPlotter" />
-      <keyword name="MicroPythonDevice.setRepl" id="MicroPythonDevice.setRepl" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.setRepl" />
-      <keyword name="MicroPythonDevice.supportsLocalFileAccess" id="MicroPythonDevice.supportsLocalFileAccess" ref="eric7.MicroPython.MicroPythonDevices.html#MicroPythonDevice.supportsLocalFileAccess" />
-      <keyword name="MicroPythonDevices (Module)" id="MicroPythonDevices (Module)" ref="eric7.MicroPython.MicroPythonDevices.html" />
       <keyword name="MicroPythonFileManager" id="MicroPythonFileManager" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager" />
       <keyword name="MicroPythonFileManager (Constructor)" id="MicroPythonFileManager (Constructor)" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.__init__" />
       <keyword name="MicroPythonFileManager (Module)" id="MicroPythonFileManager (Module)" ref="eric7.MicroPython.MicroPythonFileManager.html" />
@@ -10566,9 +10578,11 @@
       <keyword name="MicroPythonFileManager.delete" id="MicroPythonFileManager.delete" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.delete" />
       <keyword name="MicroPythonFileManager.fileSystemInfo" id="MicroPythonFileManager.fileSystemInfo" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.fileSystemInfo" />
       <keyword name="MicroPythonFileManager.get" id="MicroPythonFileManager.get" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.get" />
+      <keyword name="MicroPythonFileManager.getData" id="MicroPythonFileManager.getData" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.getData" />
       <keyword name="MicroPythonFileManager.lls" id="MicroPythonFileManager.lls" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.lls" />
       <keyword name="MicroPythonFileManager.mkdir" id="MicroPythonFileManager.mkdir" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.mkdir" />
       <keyword name="MicroPythonFileManager.put" id="MicroPythonFileManager.put" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.put" />
+      <keyword name="MicroPythonFileManager.putData" id="MicroPythonFileManager.putData" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.putData" />
       <keyword name="MicroPythonFileManager.pwd" id="MicroPythonFileManager.pwd" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.pwd" />
       <keyword name="MicroPythonFileManager.rmdir" id="MicroPythonFileManager.rmdir" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.rmdir" />
       <keyword name="MicroPythonFileManager.rsync" id="MicroPythonFileManager.rsync" ref="eric7.MicroPython.MicroPythonFileManager.html#MicroPythonFileManager.rsync" />
@@ -10612,8 +10626,11 @@
       <keyword name="MicroPythonFileManagerWidget.on_localHomeButton_clicked" id="MicroPythonFileManagerWidget.on_localHomeButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_localHomeButton_clicked" />
       <keyword name="MicroPythonFileManagerWidget.on_localReloadButton_clicked" id="MicroPythonFileManagerWidget.on_localReloadButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_localReloadButton_clicked" />
       <keyword name="MicroPythonFileManagerWidget.on_localUpButton_clicked" id="MicroPythonFileManagerWidget.on_localUpButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_localUpButton_clicked" />
+      <keyword name="MicroPythonFileManagerWidget.on_openButton_clicked" id="MicroPythonFileManagerWidget.on_openButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_openButton_clicked" />
       <keyword name="MicroPythonFileManagerWidget.on_putAsButton_clicked" id="MicroPythonFileManagerWidget.on_putAsButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_putAsButton_clicked" />
       <keyword name="MicroPythonFileManagerWidget.on_putButton_clicked" id="MicroPythonFileManagerWidget.on_putButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_putButton_clicked" />
+      <keyword name="MicroPythonFileManagerWidget.on_saveAsButton_clicked" id="MicroPythonFileManagerWidget.on_saveAsButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_saveAsButton_clicked" />
+      <keyword name="MicroPythonFileManagerWidget.on_saveButton_clicked" id="MicroPythonFileManagerWidget.on_saveButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_saveButton_clicked" />
       <keyword name="MicroPythonFileManagerWidget.on_syncButton_clicked" id="MicroPythonFileManagerWidget.on_syncButton_clicked" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.on_syncButton_clicked" />
       <keyword name="MicroPythonFileManagerWidget.start" id="MicroPythonFileManagerWidget.start" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.start" />
       <keyword name="MicroPythonFileManagerWidget.stop" id="MicroPythonFileManagerWidget.stop" ref="eric7.MicroPython.MicroPythonFileManagerWidget.html#MicroPythonFileManagerWidget.stop" />
@@ -10704,32 +10721,32 @@
       <keyword name="MicroPythonWidget.on_runButton_clicked" id="MicroPythonWidget.on_runButton_clicked" ref="eric7.MicroPython.MicroPythonWidget.html#MicroPythonWidget.on_runButton_clicked" />
       <keyword name="MicroPythonWidget.on_saveButton_clicked" id="MicroPythonWidget.on_saveButton_clicked" ref="eric7.MicroPython.MicroPythonWidget.html#MicroPythonWidget.on_saveButton_clicked" />
       <keyword name="MicroPythonWidget.setActionButtons" id="MicroPythonWidget.setActionButtons" ref="eric7.MicroPython.MicroPythonWidget.html#MicroPythonWidget.setActionButtons" />
-      <keyword name="MicrobitDevice" id="MicrobitDevice" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice" />
-      <keyword name="MicrobitDevice (Constructor)" id="MicrobitDevice (Constructor)" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__init__" />
-      <keyword name="MicrobitDevice.__createMicrobitMenu" id="MicrobitDevice.__createMicrobitMenu" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__createMicrobitMenu" />
-      <keyword name="MicrobitDevice.__firmwareVersionResponse" id="MicrobitDevice.__firmwareVersionResponse" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__firmwareVersionResponse" />
-      <keyword name="MicrobitDevice.__flashMicroPython" id="MicrobitDevice.__flashMicroPython" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__flashMicroPython" />
-      <keyword name="MicrobitDevice.__isCalliope" id="MicrobitDevice.__isCalliope" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__isCalliope" />
-      <keyword name="MicrobitDevice.__isMicroBitV1" id="MicrobitDevice.__isMicroBitV1" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__isMicroBitV1" />
-      <keyword name="MicrobitDevice.__isMicroBitV2" id="MicrobitDevice.__isMicroBitV2" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__isMicroBitV2" />
-      <keyword name="MicrobitDevice.__resetDevice" id="MicrobitDevice.__resetDevice" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__resetDevice" />
-      <keyword name="MicrobitDevice.__saveMain" id="MicrobitDevice.__saveMain" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__saveMain" />
-      <keyword name="MicrobitDevice.__saveScriptToDevice" id="MicrobitDevice.__saveScriptToDevice" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__saveScriptToDevice" />
-      <keyword name="MicrobitDevice.__showFirmwareVersions" id="MicrobitDevice.__showFirmwareVersions" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.__showFirmwareVersions" />
-      <keyword name="MicrobitDevice.addDeviceMenuEntries" id="MicrobitDevice.addDeviceMenuEntries" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.addDeviceMenuEntries" />
-      <keyword name="MicrobitDevice.canRunScript" id="MicrobitDevice.canRunScript" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.canRunScript" />
-      <keyword name="MicrobitDevice.canStartFileManager" id="MicrobitDevice.canStartFileManager" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.canStartFileManager" />
-      <keyword name="MicrobitDevice.canStartPlotter" id="MicrobitDevice.canStartPlotter" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.canStartPlotter" />
-      <keyword name="MicrobitDevice.canStartRepl" id="MicrobitDevice.canStartRepl" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.canStartRepl" />
-      <keyword name="MicrobitDevice.deviceName" id="MicrobitDevice.deviceName" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.deviceName" />
-      <keyword name="MicrobitDevice.forceInterrupt" id="MicrobitDevice.forceInterrupt" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.forceInterrupt" />
-      <keyword name="MicrobitDevice.getDocumentationUrl" id="MicrobitDevice.getDocumentationUrl" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.getDocumentationUrl" />
-      <keyword name="MicrobitDevice.getDownloadMenuEntries" id="MicrobitDevice.getDownloadMenuEntries" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.getDownloadMenuEntries" />
-      <keyword name="MicrobitDevice.hasFlashMenuEntry" id="MicrobitDevice.hasFlashMenuEntry" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.hasFlashMenuEntry" />
-      <keyword name="MicrobitDevice.hasTimeCommands" id="MicrobitDevice.hasTimeCommands" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.hasTimeCommands" />
-      <keyword name="MicrobitDevice.runScript" id="MicrobitDevice.runScript" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.runScript" />
-      <keyword name="MicrobitDevice.setButtons" id="MicrobitDevice.setButtons" ref="eric7.MicroPython.MicrobitDevices.html#MicrobitDevice.setButtons" />
-      <keyword name="MicrobitDevices (Module)" id="MicrobitDevices (Module)" ref="eric7.MicroPython.MicrobitDevices.html" />
+      <keyword name="MicrobitDevice" id="MicrobitDevice" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice" />
+      <keyword name="MicrobitDevice (Constructor)" id="MicrobitDevice (Constructor)" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__init__" />
+      <keyword name="MicrobitDevice.__createMicrobitMenu" id="MicrobitDevice.__createMicrobitMenu" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__createMicrobitMenu" />
+      <keyword name="MicrobitDevice.__firmwareVersionResponse" id="MicrobitDevice.__firmwareVersionResponse" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__firmwareVersionResponse" />
+      <keyword name="MicrobitDevice.__flashMicroPython" id="MicrobitDevice.__flashMicroPython" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__flashMicroPython" />
+      <keyword name="MicrobitDevice.__isCalliope" id="MicrobitDevice.__isCalliope" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__isCalliope" />
+      <keyword name="MicrobitDevice.__isMicroBitV1" id="MicrobitDevice.__isMicroBitV1" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__isMicroBitV1" />
+      <keyword name="MicrobitDevice.__isMicroBitV2" id="MicrobitDevice.__isMicroBitV2" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__isMicroBitV2" />
+      <keyword name="MicrobitDevice.__resetDevice" id="MicrobitDevice.__resetDevice" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__resetDevice" />
+      <keyword name="MicrobitDevice.__saveMain" id="MicrobitDevice.__saveMain" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__saveMain" />
+      <keyword name="MicrobitDevice.__saveScriptToDevice" id="MicrobitDevice.__saveScriptToDevice" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__saveScriptToDevice" />
+      <keyword name="MicrobitDevice.__showFirmwareVersions" id="MicrobitDevice.__showFirmwareVersions" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.__showFirmwareVersions" />
+      <keyword name="MicrobitDevice.addDeviceMenuEntries" id="MicrobitDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.addDeviceMenuEntries" />
+      <keyword name="MicrobitDevice.canRunScript" id="MicrobitDevice.canRunScript" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.canRunScript" />
+      <keyword name="MicrobitDevice.canStartFileManager" id="MicrobitDevice.canStartFileManager" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.canStartFileManager" />
+      <keyword name="MicrobitDevice.canStartPlotter" id="MicrobitDevice.canStartPlotter" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.canStartPlotter" />
+      <keyword name="MicrobitDevice.canStartRepl" id="MicrobitDevice.canStartRepl" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.canStartRepl" />
+      <keyword name="MicrobitDevice.deviceName" id="MicrobitDevice.deviceName" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.deviceName" />
+      <keyword name="MicrobitDevice.forceInterrupt" id="MicrobitDevice.forceInterrupt" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.forceInterrupt" />
+      <keyword name="MicrobitDevice.getDocumentationUrl" id="MicrobitDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDocumentationUrl" />
+      <keyword name="MicrobitDevice.getDownloadMenuEntries" id="MicrobitDevice.getDownloadMenuEntries" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDownloadMenuEntries" />
+      <keyword name="MicrobitDevice.hasFlashMenuEntry" id="MicrobitDevice.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.hasFlashMenuEntry" />
+      <keyword name="MicrobitDevice.hasTimeCommands" id="MicrobitDevice.hasTimeCommands" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.hasTimeCommands" />
+      <keyword name="MicrobitDevice.runScript" id="MicrobitDevice.runScript" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.runScript" />
+      <keyword name="MicrobitDevice.setButtons" id="MicrobitDevice.setButtons" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.setButtons" />
+      <keyword name="MicrobitDevices (Module)" id="MicrobitDevices (Module)" ref="eric7.MicroPython.Devices.MicrobitDevices.html" />
       <keyword name="MicrosoftEngine" id="MicrosoftEngine" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.MicrosoftEngine.html#MicrosoftEngine" />
       <keyword name="MicrosoftEngine (Constructor)" id="MicrosoftEngine (Constructor)" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.MicrosoftEngine.html#MicrosoftEngine.__init__" />
       <keyword name="MicrosoftEngine (Module)" id="MicrosoftEngine (Module)" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.MicrosoftEngine.html" />
@@ -12957,35 +12974,35 @@
       <keyword name="PurgeProjectHelper.initActions" id="PurgeProjectHelper.initActions" ref="eric7.Plugins.VcsPlugins.vcsMercurial.PurgeExtension.ProjectHelper.html#PurgeProjectHelper.initActions" />
       <keyword name="PurgeProjectHelper.initMenu" id="PurgeProjectHelper.initMenu" ref="eric7.Plugins.VcsPlugins.vcsMercurial.PurgeExtension.ProjectHelper.html#PurgeProjectHelper.initMenu" />
       <keyword name="PurgeProjectHelper.menuTitle" id="PurgeProjectHelper.menuTitle" ref="eric7.Plugins.VcsPlugins.vcsMercurial.PurgeExtension.ProjectHelper.html#PurgeProjectHelper.menuTitle" />
-      <keyword name="PyBoardDevice" id="PyBoardDevice" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice" />
-      <keyword name="PyBoardDevice (Constructor)" id="PyBoardDevice (Constructor)" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__init__" />
-      <keyword name="PyBoardDevice.__activateBootloader" id="PyBoardDevice.__activateBootloader" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__activateBootloader" />
-      <keyword name="PyBoardDevice.__createPyboardMenu" id="PyBoardDevice.__createPyboardMenu" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__createPyboardMenu" />
-      <keyword name="PyBoardDevice.__deviceVolumeMounted" id="PyBoardDevice.__deviceVolumeMounted" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__deviceVolumeMounted" />
-      <keyword name="PyBoardDevice.__dfuUtilAvailable" id="PyBoardDevice.__dfuUtilAvailable" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__dfuUtilAvailable" />
-      <keyword name="PyBoardDevice.__findWorkspace" id="PyBoardDevice.__findWorkspace" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__findWorkspace" />
-      <keyword name="PyBoardDevice.__firmwareVersionResponse" id="PyBoardDevice.__firmwareVersionResponse" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__firmwareVersionResponse" />
-      <keyword name="PyBoardDevice.__flashMicroPython" id="PyBoardDevice.__flashMicroPython" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__flashMicroPython" />
-      <keyword name="PyBoardDevice.__listDfuCapableDevices" id="PyBoardDevice.__listDfuCapableDevices" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__listDfuCapableDevices" />
-      <keyword name="PyBoardDevice.__showDfuDisableInstructions" id="PyBoardDevice.__showDfuDisableInstructions" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__showDfuDisableInstructions" />
-      <keyword name="PyBoardDevice.__showDfuEnableInstructions" id="PyBoardDevice.__showDfuEnableInstructions" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__showDfuEnableInstructions" />
-      <keyword name="PyBoardDevice.__showFirmwareVersions" id="PyBoardDevice.__showFirmwareVersions" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__showFirmwareVersions" />
-      <keyword name="PyBoardDevice.__showFlashInstructions" id="PyBoardDevice.__showFlashInstructions" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.__showFlashInstructions" />
-      <keyword name="PyBoardDevice.addDeviceMenuEntries" id="PyBoardDevice.addDeviceMenuEntries" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.addDeviceMenuEntries" />
-      <keyword name="PyBoardDevice.canRunScript" id="PyBoardDevice.canRunScript" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.canRunScript" />
-      <keyword name="PyBoardDevice.canStartFileManager" id="PyBoardDevice.canStartFileManager" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.canStartFileManager" />
-      <keyword name="PyBoardDevice.canStartPlotter" id="PyBoardDevice.canStartPlotter" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.canStartPlotter" />
-      <keyword name="PyBoardDevice.canStartRepl" id="PyBoardDevice.canStartRepl" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.canStartRepl" />
-      <keyword name="PyBoardDevice.deviceName" id="PyBoardDevice.deviceName" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.deviceName" />
-      <keyword name="PyBoardDevice.forceInterrupt" id="PyBoardDevice.forceInterrupt" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.forceInterrupt" />
-      <keyword name="PyBoardDevice.getDocumentationUrl" id="PyBoardDevice.getDocumentationUrl" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.getDocumentationUrl" />
-      <keyword name="PyBoardDevice.getFirmwareUrl" id="PyBoardDevice.getFirmwareUrl" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.getFirmwareUrl" />
-      <keyword name="PyBoardDevice.getWorkspace" id="PyBoardDevice.getWorkspace" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.getWorkspace" />
-      <keyword name="PyBoardDevice.hasFlashMenuEntry" id="PyBoardDevice.hasFlashMenuEntry" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.hasFlashMenuEntry" />
-      <keyword name="PyBoardDevice.runScript" id="PyBoardDevice.runScript" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.runScript" />
-      <keyword name="PyBoardDevice.setButtons" id="PyBoardDevice.setButtons" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.setButtons" />
-      <keyword name="PyBoardDevice.supportsLocalFileAccess" id="PyBoardDevice.supportsLocalFileAccess" ref="eric7.MicroPython.PyBoardDevices.html#PyBoardDevice.supportsLocalFileAccess" />
-      <keyword name="PyBoardDevices (Module)" id="PyBoardDevices (Module)" ref="eric7.MicroPython.PyBoardDevices.html" />
+      <keyword name="PyBoardDevice" id="PyBoardDevice" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice" />
+      <keyword name="PyBoardDevice (Constructor)" id="PyBoardDevice (Constructor)" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__init__" />
+      <keyword name="PyBoardDevice.__activateBootloader" id="PyBoardDevice.__activateBootloader" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__activateBootloader" />
+      <keyword name="PyBoardDevice.__createPyboardMenu" id="PyBoardDevice.__createPyboardMenu" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__createPyboardMenu" />
+      <keyword name="PyBoardDevice.__deviceVolumeMounted" id="PyBoardDevice.__deviceVolumeMounted" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__deviceVolumeMounted" />
+      <keyword name="PyBoardDevice.__dfuUtilAvailable" id="PyBoardDevice.__dfuUtilAvailable" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__dfuUtilAvailable" />
+      <keyword name="PyBoardDevice.__findWorkspace" id="PyBoardDevice.__findWorkspace" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__findWorkspace" />
+      <keyword name="PyBoardDevice.__firmwareVersionResponse" id="PyBoardDevice.__firmwareVersionResponse" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__firmwareVersionResponse" />
+      <keyword name="PyBoardDevice.__flashMicroPython" id="PyBoardDevice.__flashMicroPython" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__flashMicroPython" />
+      <keyword name="PyBoardDevice.__listDfuCapableDevices" id="PyBoardDevice.__listDfuCapableDevices" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__listDfuCapableDevices" />
+      <keyword name="PyBoardDevice.__showDfuDisableInstructions" id="PyBoardDevice.__showDfuDisableInstructions" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__showDfuDisableInstructions" />
+      <keyword name="PyBoardDevice.__showDfuEnableInstructions" id="PyBoardDevice.__showDfuEnableInstructions" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__showDfuEnableInstructions" />
+      <keyword name="PyBoardDevice.__showFirmwareVersions" id="PyBoardDevice.__showFirmwareVersions" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__showFirmwareVersions" />
+      <keyword name="PyBoardDevice.__showFlashInstructions" id="PyBoardDevice.__showFlashInstructions" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.__showFlashInstructions" />
+      <keyword name="PyBoardDevice.addDeviceMenuEntries" id="PyBoardDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.addDeviceMenuEntries" />
+      <keyword name="PyBoardDevice.canRunScript" id="PyBoardDevice.canRunScript" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.canRunScript" />
+      <keyword name="PyBoardDevice.canStartFileManager" id="PyBoardDevice.canStartFileManager" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.canStartFileManager" />
+      <keyword name="PyBoardDevice.canStartPlotter" id="PyBoardDevice.canStartPlotter" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.canStartPlotter" />
+      <keyword name="PyBoardDevice.canStartRepl" id="PyBoardDevice.canStartRepl" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.canStartRepl" />
+      <keyword name="PyBoardDevice.deviceName" id="PyBoardDevice.deviceName" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.deviceName" />
+      <keyword name="PyBoardDevice.forceInterrupt" id="PyBoardDevice.forceInterrupt" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.forceInterrupt" />
+      <keyword name="PyBoardDevice.getDocumentationUrl" id="PyBoardDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.getDocumentationUrl" />
+      <keyword name="PyBoardDevice.getFirmwareUrl" id="PyBoardDevice.getFirmwareUrl" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.getFirmwareUrl" />
+      <keyword name="PyBoardDevice.getWorkspace" id="PyBoardDevice.getWorkspace" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.getWorkspace" />
+      <keyword name="PyBoardDevice.hasFlashMenuEntry" id="PyBoardDevice.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.hasFlashMenuEntry" />
+      <keyword name="PyBoardDevice.runScript" id="PyBoardDevice.runScript" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.runScript" />
+      <keyword name="PyBoardDevice.setButtons" id="PyBoardDevice.setButtons" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.setButtons" />
+      <keyword name="PyBoardDevice.supportsLocalFileAccess" id="PyBoardDevice.supportsLocalFileAccess" ref="eric7.MicroPython.Devices.PyBoardDevices.html#PyBoardDevice.supportsLocalFileAccess" />
+      <keyword name="PyBoardDevices (Module)" id="PyBoardDevices (Module)" ref="eric7.MicroPython.Devices.PyBoardDevices.html" />
       <keyword name="PyCoverageDialog" id="PyCoverageDialog" ref="eric7.DataViews.PyCoverageDialog.html#PyCoverageDialog" />
       <keyword name="PyCoverageDialog (Constructor)" id="PyCoverageDialog (Constructor)" ref="eric7.DataViews.PyCoverageDialog.html#PyCoverageDialog.__init__" />
       <keyword name="PyCoverageDialog (Module)" id="PyCoverageDialog (Module)" ref="eric7.DataViews.PyCoverageDialog.html" />
@@ -13619,26 +13636,26 @@
       <keyword name="QuickFindFileDialog.on_fileNameEdit_returnPressed" id="QuickFindFileDialog.on_fileNameEdit_returnPressed" ref="eric7.Project.QuickFindFileDialog.html#QuickFindFileDialog.on_fileNameEdit_returnPressed" />
       <keyword name="QuickFindFileDialog.on_fileNameEdit_textChanged" id="QuickFindFileDialog.on_fileNameEdit_textChanged" ref="eric7.Project.QuickFindFileDialog.html#QuickFindFileDialog.on_fileNameEdit_textChanged" />
       <keyword name="QuickFindFileDialog.show" id="QuickFindFileDialog.show" ref="eric7.Project.QuickFindFileDialog.html#QuickFindFileDialog.show" />
-      <keyword name="RP2040Device" id="RP2040Device" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device" />
-      <keyword name="RP2040Device (Constructor)" id="RP2040Device (Constructor)" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.__init__" />
-      <keyword name="RP2040Device.__activateBootloader" id="RP2040Device.__activateBootloader" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.__activateBootloader" />
-      <keyword name="RP2040Device.__createRP2040Menu" id="RP2040Device.__createRP2040Menu" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.__createRP2040Menu" />
-      <keyword name="RP2040Device.__firmwareVersionResponse" id="RP2040Device.__firmwareVersionResponse" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.__firmwareVersionResponse" />
-      <keyword name="RP2040Device.__flashPython" id="RP2040Device.__flashPython" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.__flashPython" />
-      <keyword name="RP2040Device.__showFirmwareVersions" id="RP2040Device.__showFirmwareVersions" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.__showFirmwareVersions" />
-      <keyword name="RP2040Device.addDeviceMenuEntries" id="RP2040Device.addDeviceMenuEntries" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.addDeviceMenuEntries" />
-      <keyword name="RP2040Device.canRunScript" id="RP2040Device.canRunScript" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.canRunScript" />
-      <keyword name="RP2040Device.canStartFileManager" id="RP2040Device.canStartFileManager" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.canStartFileManager" />
-      <keyword name="RP2040Device.canStartPlotter" id="RP2040Device.canStartPlotter" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.canStartPlotter" />
-      <keyword name="RP2040Device.canStartRepl" id="RP2040Device.canStartRepl" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.canStartRepl" />
-      <keyword name="RP2040Device.deviceName" id="RP2040Device.deviceName" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.deviceName" />
-      <keyword name="RP2040Device.forceInterrupt" id="RP2040Device.forceInterrupt" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.forceInterrupt" />
-      <keyword name="RP2040Device.getDocumentationUrl" id="RP2040Device.getDocumentationUrl" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.getDocumentationUrl" />
-      <keyword name="RP2040Device.getDownloadMenuEntries" id="RP2040Device.getDownloadMenuEntries" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.getDownloadMenuEntries" />
-      <keyword name="RP2040Device.hasFlashMenuEntry" id="RP2040Device.hasFlashMenuEntry" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.hasFlashMenuEntry" />
-      <keyword name="RP2040Device.runScript" id="RP2040Device.runScript" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.runScript" />
-      <keyword name="RP2040Device.setButtons" id="RP2040Device.setButtons" ref="eric7.MicroPython.RP2040Devices.html#RP2040Device.setButtons" />
-      <keyword name="RP2040Devices (Module)" id="RP2040Devices (Module)" ref="eric7.MicroPython.RP2040Devices.html" />
+      <keyword name="RP2040Device" id="RP2040Device" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device" />
+      <keyword name="RP2040Device (Constructor)" id="RP2040Device (Constructor)" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.__init__" />
+      <keyword name="RP2040Device.__activateBootloader" id="RP2040Device.__activateBootloader" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.__activateBootloader" />
+      <keyword name="RP2040Device.__createRP2040Menu" id="RP2040Device.__createRP2040Menu" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.__createRP2040Menu" />
+      <keyword name="RP2040Device.__firmwareVersionResponse" id="RP2040Device.__firmwareVersionResponse" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.__firmwareVersionResponse" />
+      <keyword name="RP2040Device.__flashPython" id="RP2040Device.__flashPython" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.__flashPython" />
+      <keyword name="RP2040Device.__showFirmwareVersions" id="RP2040Device.__showFirmwareVersions" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.__showFirmwareVersions" />
+      <keyword name="RP2040Device.addDeviceMenuEntries" id="RP2040Device.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.addDeviceMenuEntries" />
+      <keyword name="RP2040Device.canRunScript" id="RP2040Device.canRunScript" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.canRunScript" />
+      <keyword name="RP2040Device.canStartFileManager" id="RP2040Device.canStartFileManager" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.canStartFileManager" />
+      <keyword name="RP2040Device.canStartPlotter" id="RP2040Device.canStartPlotter" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.canStartPlotter" />
+      <keyword name="RP2040Device.canStartRepl" id="RP2040Device.canStartRepl" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.canStartRepl" />
+      <keyword name="RP2040Device.deviceName" id="RP2040Device.deviceName" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.deviceName" />
+      <keyword name="RP2040Device.forceInterrupt" id="RP2040Device.forceInterrupt" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.forceInterrupt" />
+      <keyword name="RP2040Device.getDocumentationUrl" id="RP2040Device.getDocumentationUrl" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.getDocumentationUrl" />
+      <keyword name="RP2040Device.getDownloadMenuEntries" id="RP2040Device.getDownloadMenuEntries" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.getDownloadMenuEntries" />
+      <keyword name="RP2040Device.hasFlashMenuEntry" id="RP2040Device.hasFlashMenuEntry" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.hasFlashMenuEntry" />
+      <keyword name="RP2040Device.runScript" id="RP2040Device.runScript" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.runScript" />
+      <keyword name="RP2040Device.setButtons" id="RP2040Device.setButtons" ref="eric7.MicroPython.Devices.RP2040Devices.html#RP2040Device.setButtons" />
+      <keyword name="RP2040Devices (Module)" id="RP2040Devices (Module)" ref="eric7.MicroPython.Devices.RP2040Devices.html" />
       <keyword name="RbModule" id="RbModule" ref="eric7.Utilities.ModuleParser.html#RbModule" />
       <keyword name="RbModule (Constructor)" id="RbModule (Constructor)" ref="eric7.Utilities.ModuleParser.html#RbModule.__init__" />
       <keyword name="RbModule.addClass" id="RbModule.addClass" ref="eric7.Utilities.ModuleParser.html#RbModule.addClass" />
@@ -13697,21 +13714,21 @@
       <keyword name="ReqPackage.render_as_branch" id="ReqPackage.render_as_branch" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.render_as_branch" />
       <keyword name="ReqPackage.render_as_root" id="ReqPackage.render_as_root" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.render_as_root" />
       <keyword name="ReqPackage.version_spec" id="ReqPackage.version_spec" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.version_spec" />
-      <keyword name="RequirementsDialog" id="RequirementsDialog" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog" />
-      <keyword name="RequirementsDialog (Constructor)" id="RequirementsDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__init__" />
-      <keyword name="RequirementsDialog (Module)" id="RequirementsDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html" />
-      <keyword name="RequirementsDialog.__generateRequirements" id="RequirementsDialog.__generateRequirements" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__generateRequirements" />
-      <keyword name="RequirementsDialog.__updateButtons" id="RequirementsDialog.__updateButtons" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__updateButtons" />
-      <keyword name="RequirementsDialog.__writeToFile" id="RequirementsDialog.__writeToFile" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__writeToFile" />
-      <keyword name="RequirementsDialog.on_buttonBox_clicked" id="RequirementsDialog.on_buttonBox_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_buttonBox_clicked" />
-      <keyword name="RequirementsDialog.on_copyButton_clicked" id="RequirementsDialog.on_copyButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_copyButton_clicked" />
-      <keyword name="RequirementsDialog.on_insertButton_clicked" id="RequirementsDialog.on_insertButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_insertButton_clicked" />
-      <keyword name="RequirementsDialog.on_replaceAllButton_clicked" id="RequirementsDialog.on_replaceAllButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_replaceAllButton_clicked" />
-      <keyword name="RequirementsDialog.on_replaceSelectionButton_clicked" id="RequirementsDialog.on_replaceSelectionButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_replaceSelectionButton_clicked" />
-      <keyword name="RequirementsDialog.on_requirementsEdit_textChanged" id="RequirementsDialog.on_requirementsEdit_textChanged" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_requirementsEdit_textChanged" />
-      <keyword name="RequirementsDialog.on_requirementsFilePicker_textChanged" id="RequirementsDialog.on_requirementsFilePicker_textChanged" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_requirementsFilePicker_textChanged" />
-      <keyword name="RequirementsDialog.on_saveButton_clicked" id="RequirementsDialog.on_saveButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_saveButton_clicked" />
-      <keyword name="RequirementsDialog.on_saveToButton_clicked" id="RequirementsDialog.on_saveToButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_saveToButton_clicked" />
+      <keyword name="RequirementsDialog" id="RequirementsDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog" />
+      <keyword name="RequirementsDialog (Constructor)" id="RequirementsDialog (Constructor)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__init__" />
+      <keyword name="RequirementsDialog (Module)" id="RequirementsDialog (Module)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html" />
+      <keyword name="RequirementsDialog.__generateRequirements" id="RequirementsDialog.__generateRequirements" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__generateRequirements" />
+      <keyword name="RequirementsDialog.__updateButtons" id="RequirementsDialog.__updateButtons" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__updateButtons" />
+      <keyword name="RequirementsDialog.__writeToFile" id="RequirementsDialog.__writeToFile" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__writeToFile" />
+      <keyword name="RequirementsDialog.on_buttonBox_clicked" id="RequirementsDialog.on_buttonBox_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_buttonBox_clicked" />
+      <keyword name="RequirementsDialog.on_copyButton_clicked" id="RequirementsDialog.on_copyButton_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_copyButton_clicked" />
+      <keyword name="RequirementsDialog.on_insertButton_clicked" id="RequirementsDialog.on_insertButton_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_insertButton_clicked" />
+      <keyword name="RequirementsDialog.on_replaceAllButton_clicked" id="RequirementsDialog.on_replaceAllButton_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_replaceAllButton_clicked" />
+      <keyword name="RequirementsDialog.on_replaceSelectionButton_clicked" id="RequirementsDialog.on_replaceSelectionButton_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_replaceSelectionButton_clicked" />
+      <keyword name="RequirementsDialog.on_requirementsEdit_textChanged" id="RequirementsDialog.on_requirementsEdit_textChanged" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_requirementsEdit_textChanged" />
+      <keyword name="RequirementsDialog.on_requirementsFilePicker_textChanged" id="RequirementsDialog.on_requirementsFilePicker_textChanged" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_requirementsFilePicker_textChanged" />
+      <keyword name="RequirementsDialog.on_saveButton_clicked" id="RequirementsDialog.on_saveButton_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_saveButton_clicked" />
+      <keyword name="RequirementsDialog.on_saveToButton_clicked" id="RequirementsDialog.on_saveToButton_clicked" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_saveToButton_clicked" />
       <keyword name="RestructuredTextProvider" id="RestructuredTextProvider" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html#RestructuredTextProvider" />
       <keyword name="RestructuredTextProvider (Constructor)" id="RestructuredTextProvider (Constructor)" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html#RestructuredTextProvider.__init__" />
       <keyword name="RestructuredTextProvider (Module)" id="RestructuredTextProvider (Module)" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html" />
@@ -14405,12 +14422,12 @@
       <keyword name="ShortcutsReader.__readShortCut" id="ShortcutsReader.__readShortCut" ref="eric7.EricXML.ShortcutsReader.html#ShortcutsReader.__readShortCut" />
       <keyword name="ShortcutsReader.getShortcuts" id="ShortcutsReader.getShortcuts" ref="eric7.EricXML.ShortcutsReader.html#ShortcutsReader.getShortcuts" />
       <keyword name="ShortcutsReader.readXML" id="ShortcutsReader.readXML" ref="eric7.EricXML.ShortcutsReader.html#ShortcutsReader.readXML" />
-      <keyword name="ShowBundlesDialog" id="ShowBundlesDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html#ShowBundlesDialog" />
-      <keyword name="ShowBundlesDialog (Constructor)" id="ShowBundlesDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html#ShowBundlesDialog.__init__" />
-      <keyword name="ShowBundlesDialog (Module)" id="ShowBundlesDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html" />
-      <keyword name="ShowInstalledDialog" id="ShowInstalledDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html#ShowInstalledDialog" />
-      <keyword name="ShowInstalledDialog (Constructor)" id="ShowInstalledDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html#ShowInstalledDialog.__init__" />
-      <keyword name="ShowInstalledDialog (Module)" id="ShowInstalledDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html" />
+      <keyword name="ShowBundlesDialog" id="ShowBundlesDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html#ShowBundlesDialog" />
+      <keyword name="ShowBundlesDialog (Constructor)" id="ShowBundlesDialog (Constructor)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html#ShowBundlesDialog.__init__" />
+      <keyword name="ShowBundlesDialog (Module)" id="ShowBundlesDialog (Module)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html" />
+      <keyword name="ShowInstalledDialog" id="ShowInstalledDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html#ShowInstalledDialog" />
+      <keyword name="ShowInstalledDialog (Constructor)" id="ShowInstalledDialog (Constructor)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html#ShowInstalledDialog.__init__" />
+      <keyword name="ShowInstalledDialog (Module)" id="ShowInstalledDialog (Module)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html" />
       <keyword name="ShowModulesDialog" id="ShowModulesDialog" ref="eric7.MicroPython.ShowModulesDialog.html#ShowModulesDialog" />
       <keyword name="ShowModulesDialog (Constructor)" id="ShowModulesDialog (Constructor)" ref="eric7.MicroPython.ShowModulesDialog.html#ShowModulesDialog.__init__" />
       <keyword name="ShowModulesDialog (Module)" id="ShowModulesDialog (Module)" ref="eric7.MicroPython.ShowModulesDialog.html" />
@@ -14418,12 +14435,12 @@
       <keyword name="ShowModulesDialog.__checkCountUpdated" id="ShowModulesDialog.__checkCountUpdated" ref="eric7.MicroPython.ShowModulesDialog.html#ShowModulesDialog.__checkCountUpdated" />
       <keyword name="ShowModulesDialog.getSelection" id="ShowModulesDialog.getSelection" ref="eric7.MicroPython.ShowModulesDialog.html#ShowModulesDialog.getSelection" />
       <keyword name="ShowModulesDialog.on_modulesList_itemChanged" id="ShowModulesDialog.on_modulesList_itemChanged" ref="eric7.MicroPython.ShowModulesDialog.html#ShowModulesDialog.on_modulesList_itemChanged" />
-      <keyword name="ShowOutdatedDialog" id="ShowOutdatedDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog" />
-      <keyword name="ShowOutdatedDialog (Constructor)" id="ShowOutdatedDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.__init__" />
-      <keyword name="ShowOutdatedDialog (Module)" id="ShowOutdatedDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html" />
-      <keyword name="ShowOutdatedDialog.__checkCountUpdated" id="ShowOutdatedDialog.__checkCountUpdated" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.__checkCountUpdated" />
-      <keyword name="ShowOutdatedDialog.getSelection" id="ShowOutdatedDialog.getSelection" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.getSelection" />
-      <keyword name="ShowOutdatedDialog.on_modulesList_itemChanged" id="ShowOutdatedDialog.on_modulesList_itemChanged" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.on_modulesList_itemChanged" />
+      <keyword name="ShowOutdatedDialog" id="ShowOutdatedDialog" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog" />
+      <keyword name="ShowOutdatedDialog (Constructor)" id="ShowOutdatedDialog (Constructor)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.__init__" />
+      <keyword name="ShowOutdatedDialog (Module)" id="ShowOutdatedDialog (Module)" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html" />
+      <keyword name="ShowOutdatedDialog.__checkCountUpdated" id="ShowOutdatedDialog.__checkCountUpdated" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.__checkCountUpdated" />
+      <keyword name="ShowOutdatedDialog.getSelection" id="ShowOutdatedDialog.getSelection" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.getSelection" />
+      <keyword name="ShowOutdatedDialog.on_modulesList_itemChanged" id="ShowOutdatedDialog.on_modulesList_itemChanged" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.on_modulesList_itemChanged" />
       <keyword name="SimplePatternExtension" id="SimplePatternExtension" ref="eric7.UI.Previewers.MarkdownExtensions.html#SimplePatternExtension" />
       <keyword name="SimplePatternExtension.extendMarkdown" id="SimplePatternExtension.extendMarkdown" ref="eric7.UI.Previewers.MarkdownExtensions.html#SimplePatternExtension.extendMarkdown" />
       <keyword name="Simplify (Package)" id="Simplify (Package)" ref="index-eric7.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.html" />
@@ -16228,25 +16245,25 @@
       <keyword name="TasksReader (Module)" id="TasksReader (Module)" ref="eric7.EricXML.TasksReader.html" />
       <keyword name="TasksReader.__readTask" id="TasksReader.__readTask" ref="eric7.EricXML.TasksReader.html#TasksReader.__readTask" />
       <keyword name="TasksReader.readXML" id="TasksReader.readXML" ref="eric7.EricXML.TasksReader.html#TasksReader.readXML" />
-      <keyword name="TeensyDevice" id="TeensyDevice" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice" />
-      <keyword name="TeensyDevice (Constructor)" id="TeensyDevice (Constructor)" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.__init__" />
-      <keyword name="TeensyDevice.__createTeensyMenu" id="TeensyDevice.__createTeensyMenu" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.__createTeensyMenu" />
-      <keyword name="TeensyDevice.__firmwareVersionResponse" id="TeensyDevice.__firmwareVersionResponse" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.__firmwareVersionResponse" />
-      <keyword name="TeensyDevice.__showFirmwareVersions" id="TeensyDevice.__showFirmwareVersions" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.__showFirmwareVersions" />
-      <keyword name="TeensyDevice.__showFlashInstructions" id="TeensyDevice.__showFlashInstructions" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.__showFlashInstructions" />
-      <keyword name="TeensyDevice.__startTeensyLoader" id="TeensyDevice.__startTeensyLoader" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.__startTeensyLoader" />
-      <keyword name="TeensyDevice.addDeviceMenuEntries" id="TeensyDevice.addDeviceMenuEntries" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.addDeviceMenuEntries" />
-      <keyword name="TeensyDevice.canRunScript" id="TeensyDevice.canRunScript" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.canRunScript" />
-      <keyword name="TeensyDevice.canStartFileManager" id="TeensyDevice.canStartFileManager" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.canStartFileManager" />
-      <keyword name="TeensyDevice.canStartPlotter" id="TeensyDevice.canStartPlotter" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.canStartPlotter" />
-      <keyword name="TeensyDevice.canStartRepl" id="TeensyDevice.canStartRepl" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.canStartRepl" />
-      <keyword name="TeensyDevice.deviceName" id="TeensyDevice.deviceName" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.deviceName" />
-      <keyword name="TeensyDevice.forceInterrupt" id="TeensyDevice.forceInterrupt" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.forceInterrupt" />
-      <keyword name="TeensyDevice.getDocumentationUrl" id="TeensyDevice.getDocumentationUrl" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.getDocumentationUrl" />
-      <keyword name="TeensyDevice.getFirmwareUrl" id="TeensyDevice.getFirmwareUrl" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.getFirmwareUrl" />
-      <keyword name="TeensyDevice.runScript" id="TeensyDevice.runScript" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.runScript" />
-      <keyword name="TeensyDevice.setButtons" id="TeensyDevice.setButtons" ref="eric7.MicroPython.TeensyDevices.html#TeensyDevice.setButtons" />
-      <keyword name="TeensyDevices (Module)" id="TeensyDevices (Module)" ref="eric7.MicroPython.TeensyDevices.html" />
+      <keyword name="TeensyDevice" id="TeensyDevice" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice" />
+      <keyword name="TeensyDevice (Constructor)" id="TeensyDevice (Constructor)" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.__init__" />
+      <keyword name="TeensyDevice.__createTeensyMenu" id="TeensyDevice.__createTeensyMenu" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.__createTeensyMenu" />
+      <keyword name="TeensyDevice.__firmwareVersionResponse" id="TeensyDevice.__firmwareVersionResponse" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.__firmwareVersionResponse" />
+      <keyword name="TeensyDevice.__showFirmwareVersions" id="TeensyDevice.__showFirmwareVersions" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.__showFirmwareVersions" />
+      <keyword name="TeensyDevice.__showFlashInstructions" id="TeensyDevice.__showFlashInstructions" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.__showFlashInstructions" />
+      <keyword name="TeensyDevice.__startTeensyLoader" id="TeensyDevice.__startTeensyLoader" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.__startTeensyLoader" />
+      <keyword name="TeensyDevice.addDeviceMenuEntries" id="TeensyDevice.addDeviceMenuEntries" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.addDeviceMenuEntries" />
+      <keyword name="TeensyDevice.canRunScript" id="TeensyDevice.canRunScript" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.canRunScript" />
+      <keyword name="TeensyDevice.canStartFileManager" id="TeensyDevice.canStartFileManager" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.canStartFileManager" />
+      <keyword name="TeensyDevice.canStartPlotter" id="TeensyDevice.canStartPlotter" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.canStartPlotter" />
+      <keyword name="TeensyDevice.canStartRepl" id="TeensyDevice.canStartRepl" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.canStartRepl" />
+      <keyword name="TeensyDevice.deviceName" id="TeensyDevice.deviceName" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.deviceName" />
+      <keyword name="TeensyDevice.forceInterrupt" id="TeensyDevice.forceInterrupt" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.forceInterrupt" />
+      <keyword name="TeensyDevice.getDocumentationUrl" id="TeensyDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.getDocumentationUrl" />
+      <keyword name="TeensyDevice.getFirmwareUrl" id="TeensyDevice.getFirmwareUrl" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.getFirmwareUrl" />
+      <keyword name="TeensyDevice.runScript" id="TeensyDevice.runScript" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.runScript" />
+      <keyword name="TeensyDevice.setButtons" id="TeensyDevice.setButtons" ref="eric7.MicroPython.Devices.TeensyDevices.html#TeensyDevice.setButtons" />
+      <keyword name="TeensyDevices (Module)" id="TeensyDevices (Module)" ref="eric7.MicroPython.Devices.TeensyDevices.html" />
       <keyword name="TemplateEntry" id="TemplateEntry" ref="eric7.Templates.TemplateViewer.html#TemplateEntry" />
       <keyword name="TemplateEntry (Constructor)" id="TemplateEntry (Constructor)" ref="eric7.Templates.TemplateViewer.html#TemplateEntry.__init__" />
       <keyword name="TemplateEntry.__displayText" id="TemplateEntry.__displayText" ref="eric7.Templates.TemplateViewer.html#TemplateEntry.__displayText" />
@@ -17636,6 +17653,7 @@
       <keyword name="ViewManager.mainWidget" id="ViewManager.mainWidget" ref="eric7.ViewManager.ViewManager.html#ViewManager.mainWidget" />
       <keyword name="ViewManager.newEditor" id="ViewManager.newEditor" ref="eric7.ViewManager.ViewManager.html#ViewManager.newEditor" />
       <keyword name="ViewManager.newEditorView" id="ViewManager.newEditorView" ref="eric7.ViewManager.ViewManager.html#ViewManager.newEditorView" />
+      <keyword name="ViewManager.newEditorWithText" id="ViewManager.newEditorWithText" ref="eric7.ViewManager.ViewManager.html#ViewManager.newEditorWithText" />
       <keyword name="ViewManager.nextSplit" id="ViewManager.nextSplit" ref="eric7.ViewManager.ViewManager.html#ViewManager.nextSplit" />
       <keyword name="ViewManager.openFiles" id="ViewManager.openFiles" ref="eric7.ViewManager.ViewManager.html#ViewManager.openFiles" />
       <keyword name="ViewManager.openSourceFile" id="ViewManager.openSourceFile" ref="eric7.ViewManager.ViewManager.html#ViewManager.openSourceFile" />
@@ -18965,13 +18983,13 @@
       <keyword name="createDebuggerInterfacePython3" id="createDebuggerInterfacePython3" ref="eric7.Debugger.DebuggerInterfacePython.html#createDebuggerInterfacePython3" />
       <keyword name="createDefaultConfig" id="createDefaultConfig" ref="eric7.Plugins.VcsPlugins.vcsPySvn.SvnUtilities.html#createDefaultConfig" />
       <keyword name="createDefaultConfig" id="createDefaultConfig" ref="eric7.Plugins.VcsPlugins.vcsSubversion.SvnUtilities.html#createDefaultConfig" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.CircuitPythonDevices.html#createDevice" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.EspDevices.html#createDevice" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.GenericMicroPythonDevices.html#createDevice" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.MicrobitDevices.html#createDevice" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.PyBoardDevices.html#createDevice" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.RP2040Devices.html#createDevice" />
-      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.TeensyDevices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.CircuitPythonDevices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.EspDevices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.GenericMicroPythonDevices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.MicrobitDevices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.PyBoardDevices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.RP2040Devices.html#createDevice" />
+      <keyword name="createDevice" id="createDevice" ref="eric7.MicroPython.Devices.TeensyDevices.html#createDevice" />
       <keyword name="createEngine" id="createEngine" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.DeepLEngine.html#createEngine" />
       <keyword name="createEngine" id="createEngine" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.GoogleV1Engine.html#createEngine" />
       <keyword name="createEngine" id="createEngine" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.GoogleV2Engine.html#createEngine" />
@@ -19105,7 +19123,7 @@
       <keyword name="encryptData" id="encryptData" ref="eric7.Utilities.crypto.py3AES.html#encryptData" />
       <keyword name="engineDisplayName" id="engineDisplayName" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.__init__.html#engineDisplayName" />
       <keyword name="ensureUniqueFilename" id="ensureUniqueFilename" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#ensureUniqueFilename" />
-      <keyword name="ensure_latest_bundle" id="ensure_latest_bundle" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#ensure_latest_bundle" />
+      <keyword name="ensure_latest_bundle" id="ensure_latest_bundle" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html#ensure_latest_bundle" />
       <keyword name="enum_key_to_value" id="enum_key_to_value" ref="eric7.PipInterface.piplicenses.html#enum_key_to_value" />
       <keyword name="eradicate (Module)" id="eradicate (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.eradicate.html" />
       <keyword name="eric6SettingsName" id="eric6SettingsName" ref="eric7.Preferences.__init__.html#eric6SettingsName" />
@@ -19172,7 +19190,7 @@
       <keyword name="find_license_from_classifier" id="find_license_from_classifier" ref="eric7.PipInterface.piplicenses.html#find_license_from_classifier" />
       <keyword name="find_module" id="find_module" ref="eric7.Utilities.ClassBrowsers.__init__.html#find_module" />
       <keyword name="find_module" id="find_module" ref="eric7.Utilities.ModuleParser.html#find_module" />
-      <keyword name="find_modules" id="find_modules" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#find_modules" />
+      <keyword name="find_modules" id="find_modules" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html#find_modules" />
       <keyword name="flaskDebug (Module)" id="flaskDebug (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.flaskDebug.html" />
       <keyword name="formatTime" id="formatTime" ref="eric7.Plugins.VcsPlugins.vcsPySvn.SvnUtilities.html#formatTime" />
       <keyword name="formatargvalues" id="formatargvalues" ref="eric7.DebugClients.Python.DebugUtilities.html#formatargvalues" />
@@ -19252,8 +19270,8 @@
       <keyword name="getDefaultIconPaths" id="getDefaultIconPaths" ref="eric7.Toolbox.Startup.html#getDefaultIconPaths" />
       <keyword name="getDefaultLexerAssociations" id="getDefaultLexerAssociations" ref="eric7.QScintilla.Lexers.__init__.html#getDefaultLexerAssociations" />
       <keyword name="getDefaults" id="getDefaults" ref="eric7.Plugins.VcsPlugins.vcsMercurial.LargefilesExtension.__init__.html#getDefaults" />
-      <keyword name="getDevice" id="getDevice" ref="eric7.MicroPython.MicroPythonDevices.html#getDevice" />
-      <keyword name="getDeviceIcon" id="getDeviceIcon" ref="eric7.MicroPython.MicroPythonDevices.html#getDeviceIcon" />
+      <keyword name="getDevice" id="getDevice" ref="eric7.MicroPython.Devices.__init__.html#getDevice" />
+      <keyword name="getDeviceIcon" id="getDeviceIcon" ref="eric7.MicroPython.Devices.__init__.html#getDeviceIcon" />
       <keyword name="getDiffColour" id="getDiffColour" ref="eric7.Preferences.__init__.html#getDiffColour" />
       <keyword name="getDirs" id="getDirs" ref="eric7.SystemUtilities.FileSystemUtilities.html#getDirs" />
       <keyword name="getDocstringGenerator" id="getDocstringGenerator" ref="eric7.QScintilla.DocstringGenerator.__init__.html#getDocstringGenerator" />
@@ -19278,7 +19296,7 @@
       <keyword name="getFileNameFromUrl" id="getFileNameFromUrl" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#getFileNameFromUrl" />
       <keyword name="getFlakes" id="getFlakes" ref="eric7.Preferences.__init__.html#getFlakes" />
       <keyword name="getFormData" id="getFormData" ref="eric7.WebBrowser.Tools.Scripts.html#getFormData" />
-      <keyword name="getFoundDevices" id="getFoundDevices" ref="eric7.MicroPython.MicroPythonDevices.html#getFoundDevices" />
+      <keyword name="getFoundDevices" id="getFoundDevices" ref="eric7.MicroPython.Devices.__init__.html#getFoundDevices" />
       <keyword name="getFoundDevices" id="getFoundDevices" ref="eric7.MicroPython.UF2FlashDialog.html#getFoundDevices" />
       <keyword name="getGeometry" id="getGeometry" ref="eric7.Preferences.__init__.html#getGeometry" />
       <keyword name="getGraphics" id="getGraphics" ref="eric7.Preferences.__init__.html#getGraphics" />
@@ -19371,7 +19389,7 @@
       <keyword name="getShell" id="getShell" ref="eric7.Preferences.__init__.html#getShell" />
       <keyword name="getStrPath" id="getStrPath" ref="eric7.EricWidgets.EricPathPickerDialog.html#getStrPath" />
       <keyword name="getSupportedApiLanguages" id="getSupportedApiLanguages" ref="eric7.QScintilla.Lexers.__init__.html#getSupportedApiLanguages" />
-      <keyword name="getSupportedDevices" id="getSupportedDevices" ref="eric7.MicroPython.MicroPythonDevices.html#getSupportedDevices" />
+      <keyword name="getSupportedDevices" id="getSupportedDevices" ref="eric7.MicroPython.Devices.__init__.html#getSupportedDevices" />
       <keyword name="getSupportedDocstringTypes" id="getSupportedDocstringTypes" ref="eric7.QScintilla.DocstringGenerator.__init__.html#getSupportedDocstringTypes" />
       <keyword name="getSupportedFormats" id="getSupportedFormats" ref="eric7.QScintilla.Exporters.__init__.html#getSupportedFormats" />
       <keyword name="getSupportedLanguages" id="getSupportedLanguages" ref="eric7.QScintilla.Lexers.__init__.html#getSupportedLanguages" />
@@ -19406,7 +19424,7 @@
       <keyword name="getWebEngineVersions" id="getWebEngineVersions" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#getWebEngineVersions" />
       <keyword name="getWindowsExecutablePath" id="getWindowsExecutablePath" ref="eric7.SystemUtilities.FileSystemUtilities.html#getWindowsExecutablePath" />
       <keyword name="getWinregEntry" id="getWinregEntry" ref="eric7.eric7_post_install.html#getWinregEntry" />
-      <keyword name="get_circuitpython_version" id="get_circuitpython_version" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#get_circuitpython_version" />
+      <keyword name="get_circuitpython_version" id="get_circuitpython_version" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html#get_circuitpython_version" />
       <keyword name="get_class_members" id="get_class_members" ref="eric7.DebugClients.Python.FlexCompleter.html#get_class_members" />
       <keyword name="get_coding" id="get_coding" ref="eric7.Utilities.__init__.html#get_coding" />
       <keyword name="get_codingBytes" id="get_codingBytes" ref="eric7.Utilities.__init__.html#get_codingBytes" />
@@ -19470,7 +19488,7 @@
       <keyword name="insecureHashlibNew (Module)" id="insecureHashlibNew (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.insecureHashlibNew.html" />
       <keyword name="insecureSslTls (Module)" id="insecureSslTls (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.insecureSslTls.html" />
       <keyword name="installGoogleAPIPackages" id="installGoogleAPIPackages" ref="eric7.EricNetwork.EricGoogleMailHelpers.html#installGoogleAPIPackages" />
-      <keyword name="install_module" id="install_module" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#install_module" />
+      <keyword name="install_module" id="install_module" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html#install_module" />
       <keyword name="instance" id="instance" ref="eric7.EricNetwork.EricTldExtractor.html#instance" />
       <keyword name="instance" id="instance" ref="eric7.WebBrowser.Tools.WebIconProvider.html#instance" />
       <keyword name="instance" id="instance" ref="eric7.WebBrowser.ZoomManager.ZoomManager.html#instance" />
@@ -19480,7 +19498,7 @@
       <keyword name="isBaseString_1" id="isBaseString_1" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.AstUtilities.html#isBaseString_1" />
       <keyword name="isBytes" id="isBytes" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.AstUtilities.html#isBytes" />
       <keyword name="isBytes_1" id="isBytes_1" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.AstUtilities.html#isBytes_1" />
-      <keyword name="isCircupAvailable" id="isCircupAvailable" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#isCircupAvailable" />
+      <keyword name="isCircupAvailable" id="isCircupAvailable" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#isCircupAvailable" />
       <keyword name="isClientSecretFileAvailable" id="isClientSecretFileAvailable" ref="eric7.EricNetwork.EricGoogleMailHelpers.html#isClientSecretFileAvailable" />
       <keyword name="isCondaAvailable" id="isCondaAvailable" ref="eric7.CondaInterface.__init__.html#isCondaAvailable" />
       <keyword name="isConfigured" id="isConfigured" ref="eric7.Preferences.__init__.html#isConfigured" />
@@ -19609,7 +19627,7 @@
       <keyword name="patchNewProcessFunctions" id="patchNewProcessFunctions" ref="eric7.DebugClients.Python.MultiProcessDebugExtension.html#patchNewProcessFunctions" />
       <keyword name="patchQProcess" id="patchQProcess" ref="eric7.DebugClients.Python.QProcessExtension.html#patchQProcess" />
       <keyword name="patchSubprocess" id="patchSubprocess" ref="eric7.DebugClients.Python.SubprocessExtension.html#patchSubprocess" />
-      <keyword name="patch_circup" id="patch_circup" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#patch_circup" />
+      <keyword name="patch_circup" id="patch_circup" ref="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html#patch_circup" />
       <keyword name="pbkdf2" id="pbkdf2" ref="eric7.Utilities.crypto.py3PBKDF2.html#pbkdf2" />
       <keyword name="pipdeptree (Module)" id="pipdeptree (Module)" ref="eric7.PipInterface.pipdeptree.html" />
       <keyword name="piplicenses (Module)" id="piplicenses (Module)" ref="eric7.PipInterface.piplicenses.html" />
@@ -20104,21 +20122,26 @@
       <file>eric7.JediInterface.RefactoringPreviewDialog.html</file>
       <file>eric7.MicroPython.AddEditDevicesDialog.html</file>
       <file>eric7.MicroPython.BoardDataDialog.html</file>
-      <file>eric7.MicroPython.CircuitPythonDevices.html</file>
-      <file>eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html</file>
-      <file>eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html</file>
-      <file>eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html</file>
-      <file>eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html</file>
-      <file>eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html</file>
-      <file>eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html</file>
       <file>eric7.MicroPython.ConnectionSelectionDialog.html</file>
-      <file>eric7.MicroPython.EspBackupRestoreFirmwareDialog.html</file>
-      <file>eric7.MicroPython.EspDevices.html</file>
-      <file>eric7.MicroPython.EspFirmwareSelectionDialog.html</file>
-      <file>eric7.MicroPython.GenericMicroPythonDevices.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonDevices.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html</file>
+      <file>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html</file>
+      <file>eric7.MicroPython.Devices.DeviceBase.html</file>
+      <file>eric7.MicroPython.Devices.EspDevices.html</file>
+      <file>eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html</file>
+      <file>eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html</file>
+      <file>eric7.MicroPython.Devices.GenericMicroPythonDevices.html</file>
+      <file>eric7.MicroPython.Devices.MicrobitDevices.html</file>
+      <file>eric7.MicroPython.Devices.PyBoardDevices.html</file>
+      <file>eric7.MicroPython.Devices.RP2040Devices.html</file>
+      <file>eric7.MicroPython.Devices.TeensyDevices.html</file>
+      <file>eric7.MicroPython.Devices.__init__.html</file>
       <file>eric7.MicroPython.IgnoredDevicesDialog.html</file>
       <file>eric7.MicroPython.MicroPythonCommandsInterface.html</file>
-      <file>eric7.MicroPython.MicroPythonDevices.html</file>
       <file>eric7.MicroPython.MicroPythonFileManager.html</file>
       <file>eric7.MicroPython.MicroPythonFileManagerWidget.html</file>
       <file>eric7.MicroPython.MicroPythonFileSystemUtilities.html</file>
@@ -20126,11 +20149,7 @@
       <file>eric7.MicroPython.MicroPythonProgressInfoDialog.html</file>
       <file>eric7.MicroPython.MicroPythonSerialPort.html</file>
       <file>eric7.MicroPython.MicroPythonWidget.html</file>
-      <file>eric7.MicroPython.MicrobitDevices.html</file>
-      <file>eric7.MicroPython.PyBoardDevices.html</file>
-      <file>eric7.MicroPython.RP2040Devices.html</file>
       <file>eric7.MicroPython.ShowModulesDialog.html</file>
-      <file>eric7.MicroPython.TeensyDevices.html</file>
       <file>eric7.MicroPython.UF2FlashDialog.html</file>
       <file>eric7.MicroPython.UnknownDevicesDialog.html</file>
       <file>eric7.MultiProject.AddProjectDialog.html</file>
@@ -21108,7 +21127,9 @@
       <file>index-eric7.IconEditor.cursors.html</file>
       <file>index-eric7.IconEditor.html</file>
       <file>index-eric7.JediInterface.html</file>
-      <file>index-eric7.MicroPython.CircuitPythonUpdater.html</file>
+      <file>index-eric7.MicroPython.Devices.CircuitPythonUpdater.html</file>
+      <file>index-eric7.MicroPython.Devices.EspDialogs.html</file>
+      <file>index-eric7.MicroPython.Devices.html</file>
       <file>index-eric7.MicroPython.html</file>
       <file>index-eric7.MultiProject.html</file>
       <file>index-eric7.Network.IRC.html</file>
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,654 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonDevices</h1>
-
-<p>
-Module implementing the device interface class for CircuitPython boards.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#CircuitPythonDevice">CircuitPythonDevice</a></td>
-<td>Class implementing the device for CircuitPython boards.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="CircuitPythonDevice" ID="CircuitPythonDevice"></a>
-<h2>CircuitPythonDevice</h2>
-
-<p>
-    Class implementing the device for CircuitPython boards.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>DeviceVolumeName</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#CircuitPythonDevice.__init__">CircuitPythonDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__aboutToShowLibraryMenu">__aboutToShowLibraryMenu</a></td>
-<td>Private slot to populate the 'Library Management' menu.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__cpyVersionResponse">__cpyVersionResponse</a></td>
-<td>Private method handling the response of the latest version request.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__createCPyMenu">__createCPyMenu</a></td>
-<td>Private method to create the CircuitPython submenu.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td>
-<td>Private method to check, if the device volume is mounted.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__findDeviceDirectories">__findDeviceDirectories</a></td>
-<td>Private method to find the device directories associated with the current board name.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__findWorkspace">__findWorkspace</a></td>
-<td>Private method to find the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__flashCircuitPython">__flashCircuitPython</a></td>
-<td>Private slot to flash a CircuitPython firmware to a device supporting UF2.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__installLibraryFiles">__installLibraryFiles</a></td>
-<td>Private slot to install Python files into the onboard library.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__showCircuitPythonVersions">__showCircuitPythonVersions</a></td>
-<td>Private slot to show the CircuitPython version of a connected device and the latest available one (from Github).</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__showTeensyFlashInstructions">__showTeensyFlashInstructions</a></td>
-<td>Private method to show a message box because Teensy does not support the UF2 bootloader yet.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.__startTeensyLoader">__startTeensyLoader</a></td>
-<td>Private method to start the 'Teensy Loader' application.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
-<td>Public method to retrieve the entries for the downloads menu.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.getWorkspace">getWorkspace</a></td>
-<td>Public method to get the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
-<td>Public method to check, if the device has its own flash menu entry.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
-<td>Public method to indicate file access via a local directory.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="CircuitPythonDevice.__init__" ID="CircuitPythonDevice.__init__"></a>
-<h4>CircuitPythonDevice (Constructor)</h4>
-<b>CircuitPythonDevice</b>(<i>microPythonWidget, deviceType, boardName, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.__aboutToShowLibraryMenu" ID="CircuitPythonDevice.__aboutToShowLibraryMenu"></a>
-<h4>CircuitPythonDevice.__aboutToShowLibraryMenu</h4>
-<b>__aboutToShowLibraryMenu</b>(<i></i>)
-
-<p>
-        Private slot to populate the 'Library Management' menu.
-</p>
-<a NAME="CircuitPythonDevice.__cpyVersionResponse" ID="CircuitPythonDevice.__cpyVersionResponse"></a>
-<h4>CircuitPythonDevice.__cpyVersionResponse</h4>
-<b>__cpyVersionResponse</b>(<i>reply</i>)
-
-<p>
-        Private method handling the response of the latest version request.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the reply object
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.__createCPyMenu" ID="CircuitPythonDevice.__createCPyMenu"></a>
-<h4>CircuitPythonDevice.__createCPyMenu</h4>
-<b>__createCPyMenu</b>(<i></i>)
-
-<p>
-        Private method to create the CircuitPython submenu.
-</p>
-<a NAME="CircuitPythonDevice.__deviceVolumeMounted" ID="CircuitPythonDevice.__deviceVolumeMounted"></a>
-<h4>CircuitPythonDevice.__deviceVolumeMounted</h4>
-<b>__deviceVolumeMounted</b>(<i></i>)
-
-<p>
-        Private method to check, if the device volume is mounted.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicated a mounted device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.__findDeviceDirectories" ID="CircuitPythonDevice.__findDeviceDirectories"></a>
-<h4>CircuitPythonDevice.__findDeviceDirectories</h4>
-<b>__findDeviceDirectories</b>(<i>directories</i>)
-
-<p>
-        Private method to find the device directories associated with the
-        current board name.
-</p>
-<dl>
-
-<dt><i>directories</i> (list of str)</dt>
-<dd>
-list of directories to be checked
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of associated directories
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-list of str
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.__findWorkspace" ID="CircuitPythonDevice.__findWorkspace"></a>
-<h4>CircuitPythonDevice.__findWorkspace</h4>
-<b>__findWorkspace</b>(<i>silent=False</i>)
-
-<p>
-        Private method to find the workspace directory.
-</p>
-<dl>
-
-<dt><i>silent</i> (bool)</dt>
-<dd>
-flag indicating silent operations
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.__flashCircuitPython" ID="CircuitPythonDevice.__flashCircuitPython"></a>
-<h4>CircuitPythonDevice.__flashCircuitPython</h4>
-<b>__flashCircuitPython</b>(<i></i>)
-
-<p>
-        Private slot to flash a CircuitPython firmware to a device supporting UF2.
-</p>
-<a NAME="CircuitPythonDevice.__installLibraryFiles" ID="CircuitPythonDevice.__installLibraryFiles"></a>
-<h4>CircuitPythonDevice.__installLibraryFiles</h4>
-<b>__installLibraryFiles</b>(<i>packageMode=False</i>)
-
-<p>
-        Private slot to install Python files into the onboard library.
-</p>
-<dl>
-
-<dt><i>packageMode</i> (bool (optional))</dt>
-<dd>
-flag indicating to install a library package
-            (defaults to False)
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.__showCircuitPythonVersions" ID="CircuitPythonDevice.__showCircuitPythonVersions"></a>
-<h4>CircuitPythonDevice.__showCircuitPythonVersions</h4>
-<b>__showCircuitPythonVersions</b>(<i></i>)
-
-<p>
-        Private slot to show the CircuitPython version of a connected device and
-        the latest available one (from Github).
-</p>
-<a NAME="CircuitPythonDevice.__showTeensyFlashInstructions" ID="CircuitPythonDevice.__showTeensyFlashInstructions"></a>
-<h4>CircuitPythonDevice.__showTeensyFlashInstructions</h4>
-<b>__showTeensyFlashInstructions</b>(<i></i>)
-
-<p>
-        Private method to show a message box because Teensy does not support
-        the UF2 bootloader yet.
-</p>
-<a NAME="CircuitPythonDevice.__startTeensyLoader" ID="CircuitPythonDevice.__startTeensyLoader"></a>
-<h4>CircuitPythonDevice.__startTeensyLoader</h4>
-<b>__startTeensyLoader</b>(<i></i>)
-
-<p>
-        Private method to start the 'Teensy Loader' application.
-</p>
-<p>
-        Note: The application must be accessible via the application search path.
-</p>
-<a NAME="CircuitPythonDevice.addDeviceMenuEntries" ID="CircuitPythonDevice.addDeviceMenuEntries"></a>
-<h4>CircuitPythonDevice.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.canRunScript" ID="CircuitPythonDevice.canRunScript"></a>
-<h4>CircuitPythonDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.canStartFileManager" ID="CircuitPythonDevice.canStartFileManager"></a>
-<h4>CircuitPythonDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.canStartPlotter" ID="CircuitPythonDevice.canStartPlotter"></a>
-<h4>CircuitPythonDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.canStartRepl" ID="CircuitPythonDevice.canStartRepl"></a>
-<h4>CircuitPythonDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.deviceName" ID="CircuitPythonDevice.deviceName"></a>
-<h4>CircuitPythonDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.forceInterrupt" ID="CircuitPythonDevice.forceInterrupt"></a>
-<h4>CircuitPythonDevice.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.getDocumentationUrl" ID="CircuitPythonDevice.getDocumentationUrl"></a>
-<h4>CircuitPythonDevice.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.getDownloadMenuEntries" ID="CircuitPythonDevice.getDownloadMenuEntries"></a>
-<h4>CircuitPythonDevice.getDownloadMenuEntries</h4>
-<b>getDownloadMenuEntries</b>(<i></i>)
-
-<p>
-        Public method to retrieve the entries for the downloads menu.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of tuples with menu text and URL to be opened for each
-            entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-list of tuple of (str, str)
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.getWorkspace" ID="CircuitPythonDevice.getWorkspace"></a>
-<h4>CircuitPythonDevice.getWorkspace</h4>
-<b>getWorkspace</b>(<i>silent=False</i>)
-
-<p>
-        Public method to get the workspace directory.
-</p>
-<dl>
-
-<dt><i>silent</i> (bool)</dt>
-<dd>
-flag indicating silent operations
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.hasFlashMenuEntry" ID="CircuitPythonDevice.hasFlashMenuEntry"></a>
-<h4>CircuitPythonDevice.hasFlashMenuEntry</h4>
-<b>hasFlashMenuEntry</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has its own flash menu entry.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a specific flash menu entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.runScript" ID="CircuitPythonDevice.runScript"></a>
-<h4>CircuitPythonDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="CircuitPythonDevice.setButtons" ID="CircuitPythonDevice.setButtons"></a>
-<h4>CircuitPythonDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<a NAME="CircuitPythonDevice.supportsLocalFileAccess" ID="CircuitPythonDevice.supportsLocalFileAccess"></a>
-<h4>CircuitPythonDevice.supportsLocalFileAccess</h4>
-<b>supportsLocalFileAccess</b>(<i></i>)
-
-<p>
-        Public method to indicate file access via a local directory.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating file access via local directory
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-CircuitPythonDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,358 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface</h1>
-
-<p>
-Module implementing an interface to the 'circup' package.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface">CircuitPythonUpdaterInterface</a></td>
-<td>Class implementing an interface to the 'circup' package.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#isCircupAvailable">isCircupAvailable</a></td>
-<td>Function to check for the availability of 'circup'.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="CircuitPythonUpdaterInterface" ID="CircuitPythonUpdaterInterface"></a>
-<h2>CircuitPythonUpdaterInterface</h2>
-
-<p>
-    Class implementing an interface to the 'circup' package.
-</p>
-<h3>Derived from</h3>
-QObject
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__init__">CircuitPythonUpdaterInterface</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__aboutCircup">__aboutCircup</a></td>
-<td>Private slot to show some info about 'circup'.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__addBundle">__addBundle</a></td>
-<td>Private slot to add a bundle to the local bundles list, by "user/repo" github string.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__doUpdateModules">__doUpdateModules</a></td>
-<td>Private method to perform the update of a list of modules.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__generateRequirements">__generateRequirements</a></td>
-<td>Private slot to generate requirements for the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__installFromAvailable">__installFromAvailable</a></td>
-<td>Private slot to install modules onto the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__installFromCode">__installFromCode</a></td>
-<td>Private slot to install modules based on the 'code.py' file of the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__installModules">__installModules</a></td>
-<td>Private method to install the given list of modules.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__installRequirements">__installRequirements</a></td>
-<td>Private slot to install modules determined by a requirements file.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__listOutdatedModules">__listOutdatedModules</a></td>
-<td>Private slot to list the outdated modules of the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__removeBundle">__removeBundle</a></td>
-<td>Private slot to remove one or more bundles from the local bundles list.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__showAvailableModules">__showAvailableModules</a></td>
-<td>Private slot to show the available modules.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__showBundles">__showBundles</a></td>
-<td>Private slot to show the available bundles (default and local).</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__showBundlesModules">__showBundlesModules</a></td>
-<td>Private slot to show the available bundles (default and local) with their modules.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__showInstalledModules">__showInstalledModules</a></td>
-<td>Private slot to show the modules installed on the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__uninstallModules">__uninstallModules</a></td>
-<td>Private slot to uninstall modules from the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__updateAllModules">__updateAllModules</a></td>
-<td>Private slot to update all modules of the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.__updateModules">__updateModules</a></td>
-<td>Private slot to update the modules of the connected device.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.installCircup">installCircup</a></td>
-<td>Public slot to install the 'circup' package via pip.</td>
-</tr>
-<tr>
-<td><a href="#CircuitPythonUpdaterInterface.populateMenu">populateMenu</a></td>
-<td>Public method to populate the 'circup' menu.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="CircuitPythonUpdaterInterface.__init__" ID="CircuitPythonUpdaterInterface.__init__"></a>
-<h4>CircuitPythonUpdaterInterface (Constructor)</h4>
-<b>CircuitPythonUpdaterInterface</b>(<i>device, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>device</i> (CircuitPythonDevice)</dt>
-<dd>
-reference to the CircuitPython device interface
-</dd>
-<dt><i>parent</i> (QObject (optional))</dt>
-<dd>
-reference to the parent object (defaults to None)
-</dd>
-</dl>
-<a NAME="CircuitPythonUpdaterInterface.__aboutCircup" ID="CircuitPythonUpdaterInterface.__aboutCircup"></a>
-<h4>CircuitPythonUpdaterInterface.__aboutCircup</h4>
-<b>__aboutCircup</b>(<i></i>)
-
-<p>
-        Private slot to show some info about 'circup'.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__addBundle" ID="CircuitPythonUpdaterInterface.__addBundle"></a>
-<h4>CircuitPythonUpdaterInterface.__addBundle</h4>
-<b>__addBundle</b>(<i></i>)
-
-<p>
-        Private slot to add a bundle to the local bundles list, by "user/repo" github
-        string.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__doUpdateModules" ID="CircuitPythonUpdaterInterface.__doUpdateModules"></a>
-<h4>CircuitPythonUpdaterInterface.__doUpdateModules</h4>
-<b>__doUpdateModules</b>(<i>modules</i>)
-
-<p>
-        Private method to perform the update of a list of modules.
-</p>
-<dl>
-
-<dt><i>modules</i> (circup.Module)</dt>
-<dd>
-list of modules to be updated
-</dd>
-</dl>
-<a NAME="CircuitPythonUpdaterInterface.__generateRequirements" ID="CircuitPythonUpdaterInterface.__generateRequirements"></a>
-<h4>CircuitPythonUpdaterInterface.__generateRequirements</h4>
-<b>__generateRequirements</b>(<i></i>)
-
-<p>
-        Private slot to generate requirements for the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__installFromAvailable" ID="CircuitPythonUpdaterInterface.__installFromAvailable"></a>
-<h4>CircuitPythonUpdaterInterface.__installFromAvailable</h4>
-<b>__installFromAvailable</b>(<i></i>)
-
-<p>
-        Private slot to install modules onto the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__installFromCode" ID="CircuitPythonUpdaterInterface.__installFromCode"></a>
-<h4>CircuitPythonUpdaterInterface.__installFromCode</h4>
-<b>__installFromCode</b>(<i></i>)
-
-<p>
-        Private slot to install modules based on the 'code.py' file of the
-        connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__installModules" ID="CircuitPythonUpdaterInterface.__installModules"></a>
-<h4>CircuitPythonUpdaterInterface.__installModules</h4>
-<b>__installModules</b>(<i>installs</i>)
-
-<p>
-        Private method to install the given list of modules.
-</p>
-<dl>
-
-<dt><i>installs</i> (list of str)</dt>
-<dd>
-list of module names to be installed
-</dd>
-</dl>
-<a NAME="CircuitPythonUpdaterInterface.__installRequirements" ID="CircuitPythonUpdaterInterface.__installRequirements"></a>
-<h4>CircuitPythonUpdaterInterface.__installRequirements</h4>
-<b>__installRequirements</b>(<i></i>)
-
-<p>
-        Private slot to install modules determined by a requirements file.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__listOutdatedModules" ID="CircuitPythonUpdaterInterface.__listOutdatedModules"></a>
-<h4>CircuitPythonUpdaterInterface.__listOutdatedModules</h4>
-<b>__listOutdatedModules</b>(<i></i>)
-
-<p>
-        Private slot to list the outdated modules of the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__removeBundle" ID="CircuitPythonUpdaterInterface.__removeBundle"></a>
-<h4>CircuitPythonUpdaterInterface.__removeBundle</h4>
-<b>__removeBundle</b>(<i></i>)
-
-<p>
-        Private slot to remove one or more bundles from the local bundles list.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__showAvailableModules" ID="CircuitPythonUpdaterInterface.__showAvailableModules"></a>
-<h4>CircuitPythonUpdaterInterface.__showAvailableModules</h4>
-<b>__showAvailableModules</b>(<i></i>)
-
-<p>
-        Private slot to show the available modules.
-</p>
-<p>
-        These are modules which could be installed on the device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__showBundles" ID="CircuitPythonUpdaterInterface.__showBundles"></a>
-<h4>CircuitPythonUpdaterInterface.__showBundles</h4>
-<b>__showBundles</b>(<i>withModules=False</i>)
-
-<p>
-        Private slot to show the available bundles (default and local).
-</p>
-<dl>
-
-<dt><i>withModules</i> (bool (optional))</dt>
-<dd>
-flag indicating to list the modules and their version
-            (defaults to False)
-</dd>
-</dl>
-<a NAME="CircuitPythonUpdaterInterface.__showBundlesModules" ID="CircuitPythonUpdaterInterface.__showBundlesModules"></a>
-<h4>CircuitPythonUpdaterInterface.__showBundlesModules</h4>
-<b>__showBundlesModules</b>(<i></i>)
-
-<p>
-        Private slot to show the available bundles (default and local) with their
-        modules.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__showInstalledModules" ID="CircuitPythonUpdaterInterface.__showInstalledModules"></a>
-<h4>CircuitPythonUpdaterInterface.__showInstalledModules</h4>
-<b>__showInstalledModules</b>(<i></i>)
-
-<p>
-        Private slot to show the modules installed on the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__uninstallModules" ID="CircuitPythonUpdaterInterface.__uninstallModules"></a>
-<h4>CircuitPythonUpdaterInterface.__uninstallModules</h4>
-<b>__uninstallModules</b>(<i></i>)
-
-<p>
-        Private slot to uninstall modules from the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__updateAllModules" ID="CircuitPythonUpdaterInterface.__updateAllModules"></a>
-<h4>CircuitPythonUpdaterInterface.__updateAllModules</h4>
-<b>__updateAllModules</b>(<i></i>)
-
-<p>
-        Private slot to update all modules of the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.__updateModules" ID="CircuitPythonUpdaterInterface.__updateModules"></a>
-<h4>CircuitPythonUpdaterInterface.__updateModules</h4>
-<b>__updateModules</b>(<i></i>)
-
-<p>
-        Private slot to update the modules of the connected device.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.installCircup" ID="CircuitPythonUpdaterInterface.installCircup"></a>
-<h4>CircuitPythonUpdaterInterface.installCircup</h4>
-<b>installCircup</b>(<i></i>)
-
-<p>
-        Public slot to install the 'circup' package via pip.
-</p>
-<a NAME="CircuitPythonUpdaterInterface.populateMenu" ID="CircuitPythonUpdaterInterface.populateMenu"></a>
-<h4>CircuitPythonUpdaterInterface.populateMenu</h4>
-<b>populateMenu</b>(<i>menu</i>)
-
-<p>
-        Public method to populate the 'circup' menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the menu to be populated
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="isCircupAvailable" ID="isCircupAvailable"></a>
-<h2>isCircupAvailable</h2>
-<b>isCircupAvailable</b>(<i></i>)
-
-<p>
-    Function to check for the availability of 'circup'.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating the availability of 'circup'
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,209 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater.CircupFunctions</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonUpdater.CircupFunctions</h1>
-
-<p>
-Module implementing variants of some 'circup' functions suitable for 'eric-ide'
-integration.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#ensure_latest_bundle">ensure_latest_bundle</a></td>
-<td>Function to ensure that there's a copy of the latest library bundle available so circup can check the metadata contained therein.</td>
-</tr>
-<tr>
-<td><a href="#find_modules">find_modules</a></td>
-<td>Function to extract metadata from the connected device and available bundles and returns this as a list of Module instances representing the modules on the device.</td>
-</tr>
-<tr>
-<td><a href="#get_circuitpython_version">get_circuitpython_version</a></td>
-<td>Function to return the version number of CircuitPython running on the board connected via ``device_path``, along with the board ID.</td>
-</tr>
-<tr>
-<td><a href="#install_module">install_module</a></td>
-<td>Function to find a connected device and install a given module name.</td>
-</tr>
-<tr>
-<td><a href="#patch_circup">patch_circup</a></td>
-<td>Function to patch 'circup' to use our functions adapted to the use within the eric-ide.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="ensure_latest_bundle" ID="ensure_latest_bundle"></a>
-<h2>ensure_latest_bundle</h2>
-<b>ensure_latest_bundle</b>(<i>bundle</i>)
-
-<p>
-    Function to ensure that there's a copy of the latest library bundle available so
-    circup can check the metadata contained therein.
-</p>
-<dl>
-
-<dt><i>bundle</i> (circup.Bundle)</dt>
-<dd>
-reference to the target Bundle object.
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="find_modules" ID="find_modules"></a>
-<h2>find_modules</h2>
-<b>find_modules</b>(<i>device_path, bundles_list</i>)
-
-<p>
-    Function to extract metadata from the connected device and available bundles and
-    returns this as a list of Module instances representing the modules on the device.
-</p>
-<dl>
-
-<dt><i>device_path</i> (str)</dt>
-<dd>
-path to the connected board
-</dd>
-<dt><i>bundles_list</i> (list of circup.Bundle)</dt>
-<dd>
-list of supported bundles
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of Module instances describing the current state of the
-        modules on the connected device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-list of circup.Module
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="get_circuitpython_version" ID="get_circuitpython_version"></a>
-<h2>get_circuitpython_version</h2>
-<b>get_circuitpython_version</b>(<i>device_path</i>)
-
-<p>
-    Function to return the version number of CircuitPython running on the board
-    connected via ``device_path``, along with the board ID.
-</p>
-<p>
-    This is obtained from the 'boot_out.txt' file on the device, whose first line
-    will start with something like this:
-</p>
-<p>
-        Adafruit CircuitPython 4.1.0 on 2019-08-02;
-</p>
-<p>
-    While the second line is:
-</p>
-<p>
-        Board ID:raspberry_pi_pico
-</p>
-<dl>
-
-<dt><i>device_path</i> (str)</dt>
-<dd>
-path to the connected board.
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple with the version string for CircuitPython and the board ID string
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (str, str)
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="install_module" ID="install_module"></a>
-<h2>install_module</h2>
-<b>install_module</b>(<i>device_path, device_modules, name, py, mod_names</i>)
-
-<p>
-    Function to find a connected device and install a given module name.
-</p>
-<p>
-    Installation is done if it is available in the current module bundle and is not
-    already installed on the device.
-</p>
-<dl>
-
-<dt><i>device_path</i> (str)</dt>
-<dd>
-path to the connected board
-</dd>
-<dt><i>device_modules</i> (list of dict)</dt>
-<dd>
-list of module metadata from the device
-</dd>
-<dt><i>name</i> (str)</dt>
-<dd>
-name of the module to be installed
-</dd>
-<dt><i>py</i> (bool)</dt>
-<dd>
-flag indicating if the module should be installed from source or
-        from a pre-compiled module
-</dd>
-<dt><i>mod_names</i> (dict)</dt>
-<dd>
-dictionary containing metadata from modules that can be generated
-        with circup.get_bundle_versions()
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating success
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="patch_circup" ID="patch_circup"></a>
-<h2>patch_circup</h2>
-<b>patch_circup</b>(<i></i>)
-
-<p>
-    Function to patch 'circup' to use our functions adapted to the use within the
-    eric-ide.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,244 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog</h1>
-
-<p>
-Module implementing a dialog to generate a requirements file.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#RequirementsDialog">RequirementsDialog</a></td>
-<td>Class implementing a dialog to generate a requirements file.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr />
-<hr />
-<a NAME="RequirementsDialog" ID="RequirementsDialog"></a>
-<h2>RequirementsDialog</h2>
-
-<p>
-    Class implementing a dialog to generate a requirements file.
-</p>
-<h3>Derived from</h3>
-QDialog, Ui_RequirementsDialog
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#RequirementsDialog.__init__">RequirementsDialog</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.__generateRequirements">__generateRequirements</a></td>
-<td>Private slot to generate the requirements specifiers list.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.__updateButtons">__updateButtons</a></td>
-<td>Private method to set the state of the various buttons.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.__writeToFile">__writeToFile</a></td>
-<td>Private method to write the requirements text to a file.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_buttonBox_clicked">on_buttonBox_clicked</a></td>
-<td>Private slot called by a button of the button box clicked.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_copyButton_clicked">on_copyButton_clicked</a></td>
-<td>Private slot to copy the requirements text to the clipboard.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_insertButton_clicked">on_insertButton_clicked</a></td>
-<td>Private slot to insert the requirements text at the cursor position of the current editor.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_replaceAllButton_clicked">on_replaceAllButton_clicked</a></td>
-<td>Private slot to replace the text of the current editor with the requirements text.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_replaceSelectionButton_clicked">on_replaceSelectionButton_clicked</a></td>
-<td>Private slot to replace the selected text of the current editor with the requirements text.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_requirementsEdit_textChanged">on_requirementsEdit_textChanged</a></td>
-<td>Private slot handling changes of the requirements text.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_requirementsFilePicker_textChanged">on_requirementsFilePicker_textChanged</a></td>
-<td>Private slot handling a change of the requirements file name.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_saveButton_clicked">on_saveButton_clicked</a></td>
-<td>Private slot to save the requirements text to the requirements file.</td>
-</tr>
-<tr>
-<td><a href="#RequirementsDialog.on_saveToButton_clicked">on_saveToButton_clicked</a></td>
-<td>Private slot to write the requirements text to a new file.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="RequirementsDialog.__init__" ID="RequirementsDialog.__init__"></a>
-<h4>RequirementsDialog (Constructor)</h4>
-<b>RequirementsDialog</b>(<i>devicePath, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>devicePath</i> (str)</dt>
-<dd>
-path to the connected board
-</dd>
-<dt><i>parent</i> (QWidget (optional))</dt>
-<dd>
-reference to the parent widget (defaults to None)
-</dd>
-</dl>
-<a NAME="RequirementsDialog.__generateRequirements" ID="RequirementsDialog.__generateRequirements"></a>
-<h4>RequirementsDialog.__generateRequirements</h4>
-<b>__generateRequirements</b>(<i></i>)
-
-<p>
-        Private slot to generate the requirements specifiers list.
-</p>
-<a NAME="RequirementsDialog.__updateButtons" ID="RequirementsDialog.__updateButtons"></a>
-<h4>RequirementsDialog.__updateButtons</h4>
-<b>__updateButtons</b>(<i></i>)
-
-<p>
-        Private method to set the state of the various buttons.
-</p>
-<a NAME="RequirementsDialog.__writeToFile" ID="RequirementsDialog.__writeToFile"></a>
-<h4>RequirementsDialog.__writeToFile</h4>
-<b>__writeToFile</b>(<i>fileName</i>)
-
-<p>
-        Private method to write the requirements text to a file.
-</p>
-<dl>
-
-<dt><i>fileName</i> (str)</dt>
-<dd>
-name of the file to write to
-</dd>
-</dl>
-<a NAME="RequirementsDialog.on_buttonBox_clicked" ID="RequirementsDialog.on_buttonBox_clicked"></a>
-<h4>RequirementsDialog.on_buttonBox_clicked</h4>
-<b>on_buttonBox_clicked</b>(<i>button</i>)
-
-<p>
-        Private slot called by a button of the button box clicked.
-</p>
-<dl>
-
-<dt><i>button</i> (QAbstractButton)</dt>
-<dd>
-button that was clicked
-</dd>
-</dl>
-<a NAME="RequirementsDialog.on_copyButton_clicked" ID="RequirementsDialog.on_copyButton_clicked"></a>
-<h4>RequirementsDialog.on_copyButton_clicked</h4>
-<b>on_copyButton_clicked</b>(<i></i>)
-
-<p>
-        Private slot to copy the requirements text to the clipboard.
-</p>
-<a NAME="RequirementsDialog.on_insertButton_clicked" ID="RequirementsDialog.on_insertButton_clicked"></a>
-<h4>RequirementsDialog.on_insertButton_clicked</h4>
-<b>on_insertButton_clicked</b>(<i></i>)
-
-<p>
-        Private slot to insert the requirements text at the cursor position
-        of the current editor.
-</p>
-<a NAME="RequirementsDialog.on_replaceAllButton_clicked" ID="RequirementsDialog.on_replaceAllButton_clicked"></a>
-<h4>RequirementsDialog.on_replaceAllButton_clicked</h4>
-<b>on_replaceAllButton_clicked</b>(<i></i>)
-
-<p>
-        Private slot to replace the text of the current editor with the
-        requirements text.
-</p>
-<a NAME="RequirementsDialog.on_replaceSelectionButton_clicked" ID="RequirementsDialog.on_replaceSelectionButton_clicked"></a>
-<h4>RequirementsDialog.on_replaceSelectionButton_clicked</h4>
-<b>on_replaceSelectionButton_clicked</b>(<i></i>)
-
-<p>
-        Private slot to replace the selected text of the current editor
-        with the requirements text.
-</p>
-<a NAME="RequirementsDialog.on_requirementsEdit_textChanged" ID="RequirementsDialog.on_requirementsEdit_textChanged"></a>
-<h4>RequirementsDialog.on_requirementsEdit_textChanged</h4>
-<b>on_requirementsEdit_textChanged</b>(<i></i>)
-
-<p>
-        Private slot handling changes of the requirements text.
-</p>
-<a NAME="RequirementsDialog.on_requirementsFilePicker_textChanged" ID="RequirementsDialog.on_requirementsFilePicker_textChanged"></a>
-<h4>RequirementsDialog.on_requirementsFilePicker_textChanged</h4>
-<b>on_requirementsFilePicker_textChanged</b>(<i>txt</i>)
-
-<p>
-        Private slot handling a change of the requirements file name.
-</p>
-<dl>
-
-<dt><i>txt</i> (str)</dt>
-<dd>
-name of the requirements file
-</dd>
-</dl>
-<a NAME="RequirementsDialog.on_saveButton_clicked" ID="RequirementsDialog.on_saveButton_clicked"></a>
-<h4>RequirementsDialog.on_saveButton_clicked</h4>
-<b>on_saveButton_clicked</b>(<i></i>)
-
-<p>
-        Private slot to save the requirements text to the requirements file.
-</p>
-<a NAME="RequirementsDialog.on_saveToButton_clicked" ID="RequirementsDialog.on_saveToButton_clicked"></a>
-<h4>RequirementsDialog.on_saveToButton_clicked</h4>
-<b>on_saveToButton_clicked</b>(<i></i>)
-
-<p>
-        Private slot to write the requirements text to a new file.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog</h1>
-
-<p>
-Module implementing a dialog showing the available bundles and their modules.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#ShowBundlesDialog">ShowBundlesDialog</a></td>
-<td>Class implementing a dialog showing the available bundles and their modules.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr />
-<hr />
-<a NAME="ShowBundlesDialog" ID="ShowBundlesDialog"></a>
-<h2>ShowBundlesDialog</h2>
-
-<p>
-    Class implementing a dialog showing the available bundles and their modules.
-</p>
-<h3>Derived from</h3>
-QDialog, Ui_ShowBundlesDialog
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#ShowBundlesDialog.__init__">ShowBundlesDialog</a></td>
-<td>Constructor</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="ShowBundlesDialog.__init__" ID="ShowBundlesDialog.__init__"></a>
-<h4>ShowBundlesDialog (Constructor)</h4>
-<b>ShowBundlesDialog</b>(<i>withModules, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>withModules</i> (bool)</dt>
-<dd>
-flag indicating to list the modules and their version
-</dd>
-<dt><i>parent</i> (QWidget (optional))</dt>
-<dd>
-reference to the parent widget (defaults to None)
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog</h1>
-
-<p>
-Module implementing a dialog to show the modules installed on the connected device.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#ShowInstalledDialog">ShowInstalledDialog</a></td>
-<td>Class implementing a dialog to show the modules installed on the connected device.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr />
-<hr />
-<a NAME="ShowInstalledDialog" ID="ShowInstalledDialog"></a>
-<h2>ShowInstalledDialog</h2>
-
-<p>
-    Class implementing a dialog to show the modules installed on the connected device.
-</p>
-<h3>Derived from</h3>
-QDialog, Ui_ShowInstalledDialog
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#ShowInstalledDialog.__init__">ShowInstalledDialog</a></td>
-<td>Constructor</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="ShowInstalledDialog.__init__" ID="ShowInstalledDialog.__init__"></a>
-<h4>ShowInstalledDialog (Constructor)</h4>
-<b>ShowInstalledDialog</b>(<i>devicePath, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>devicePath</i> (str)</dt>
-<dd>
-path to the connected board
-</dd>
-<dt><i>parent</i> (QWidget (optional))</dt>
-<dd>
-reference to the parent widget (defaults to None)
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog</h1>
-
-<p>
-Module implementing a dialog to show outdated modules of a connected device.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#ShowOutdatedDialog">ShowOutdatedDialog</a></td>
-<td>Class implementing a dialog to show outdated modules of a connected device.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr />
-<hr />
-<a NAME="ShowOutdatedDialog" ID="ShowOutdatedDialog"></a>
-<h2>ShowOutdatedDialog</h2>
-
-<p>
-    Class implementing a dialog to show outdated modules of a connected device.
-</p>
-<h3>Derived from</h3>
-QDialog, Ui_ShowOutdatedDialog
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#ShowOutdatedDialog.__init__">ShowOutdatedDialog</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#ShowOutdatedDialog.__checkCountUpdated">__checkCountUpdated</a></td>
-<td>Private method to handle an update of the check count.</td>
-</tr>
-<tr>
-<td><a href="#ShowOutdatedDialog.getSelection">getSelection</a></td>
-<td>Public method to get the list of selected modules.</td>
-</tr>
-<tr>
-<td><a href="#ShowOutdatedDialog.on_modulesList_itemChanged">on_modulesList_itemChanged</a></td>
-<td>Private slot to handle a change of the check state of an item.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="ShowOutdatedDialog.__init__" ID="ShowOutdatedDialog.__init__"></a>
-<h4>ShowOutdatedDialog (Constructor)</h4>
-<b>ShowOutdatedDialog</b>(<i>devicePath, selectionMode=False, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>devicePath</i> (str)</dt>
-<dd>
-path to the connected board
-</dd>
-<dt><i>selectionMode</i> (bool (optional))</dt>
-<dd>
-flag indicating the activation of the selection mode
-            (defaults to False)
-</dd>
-<dt><i>parent</i> (QWidget (optional))</dt>
-<dd>
-reference to the parent widget (defaults to None)
-</dd>
-</dl>
-<a NAME="ShowOutdatedDialog.__checkCountUpdated" ID="ShowOutdatedDialog.__checkCountUpdated"></a>
-<h4>ShowOutdatedDialog.__checkCountUpdated</h4>
-<b>__checkCountUpdated</b>(<i></i>)
-
-<p>
-        Private method to handle an update of the check count.
-</p>
-<a NAME="ShowOutdatedDialog.getSelection" ID="ShowOutdatedDialog.getSelection"></a>
-<h4>ShowOutdatedDialog.getSelection</h4>
-<b>getSelection</b>(<i></i>)
-
-<p>
-        Public method to get the list of selected modules.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of selected modules
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-circup.Module
-</dd>
-</dl>
-<a NAME="ShowOutdatedDialog.on_modulesList_itemChanged" ID="ShowOutdatedDialog.on_modulesList_itemChanged"></a>
-<h4>ShowOutdatedDialog.on_modulesList_itemChanged</h4>
-<b>on_modulesList_itemChanged</b>(<i>item, column</i>)
-
-<p>
-        Private slot to handle a change of the check state of an item.
-</p>
-<dl>
-
-<dt><i>item</i> (QTreeWidgetItem)</dt>
-<dd>
-reference to the changed item
-</dd>
-<dt><i>column</i> (int)</dt>
-<dd>
-changed column
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonDevices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,654 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonDevices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonDevices</h1>
+
+<p>
+Module implementing the device interface class for CircuitPython boards.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#CircuitPythonDevice">CircuitPythonDevice</a></td>
+<td>Class implementing the device for CircuitPython boards.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="CircuitPythonDevice" ID="CircuitPythonDevice"></a>
+<h2>CircuitPythonDevice</h2>
+
+<p>
+    Class implementing the device for CircuitPython boards.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>DeviceVolumeName</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#CircuitPythonDevice.__init__">CircuitPythonDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__aboutToShowLibraryMenu">__aboutToShowLibraryMenu</a></td>
+<td>Private slot to populate the 'Library Management' menu.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__cpyVersionResponse">__cpyVersionResponse</a></td>
+<td>Private method handling the response of the latest version request.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__createCPyMenu">__createCPyMenu</a></td>
+<td>Private method to create the CircuitPython submenu.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td>
+<td>Private method to check, if the device volume is mounted.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__findDeviceDirectories">__findDeviceDirectories</a></td>
+<td>Private method to find the device directories associated with the current board name.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__findWorkspace">__findWorkspace</a></td>
+<td>Private method to find the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__flashCircuitPython">__flashCircuitPython</a></td>
+<td>Private slot to flash a CircuitPython firmware to a device supporting UF2.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__installLibraryFiles">__installLibraryFiles</a></td>
+<td>Private slot to install Python files into the onboard library.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__showCircuitPythonVersions">__showCircuitPythonVersions</a></td>
+<td>Private slot to show the CircuitPython version of a connected device and the latest available one (from Github).</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__showTeensyFlashInstructions">__showTeensyFlashInstructions</a></td>
+<td>Private method to show a message box because Teensy does not support the UF2 bootloader yet.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.__startTeensyLoader">__startTeensyLoader</a></td>
+<td>Private method to start the 'Teensy Loader' application.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
+<td>Public method to retrieve the entries for the downloads menu.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.getWorkspace">getWorkspace</a></td>
+<td>Public method to get the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
+<td>Public method to check, if the device has its own flash menu entry.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
+<td>Public method to indicate file access via a local directory.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="CircuitPythonDevice.__init__" ID="CircuitPythonDevice.__init__"></a>
+<h4>CircuitPythonDevice (Constructor)</h4>
+<b>CircuitPythonDevice</b>(<i>microPythonWidget, deviceType, boardName, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.__aboutToShowLibraryMenu" ID="CircuitPythonDevice.__aboutToShowLibraryMenu"></a>
+<h4>CircuitPythonDevice.__aboutToShowLibraryMenu</h4>
+<b>__aboutToShowLibraryMenu</b>(<i></i>)
+
+<p>
+        Private slot to populate the 'Library Management' menu.
+</p>
+<a NAME="CircuitPythonDevice.__cpyVersionResponse" ID="CircuitPythonDevice.__cpyVersionResponse"></a>
+<h4>CircuitPythonDevice.__cpyVersionResponse</h4>
+<b>__cpyVersionResponse</b>(<i>reply</i>)
+
+<p>
+        Private method handling the response of the latest version request.
+</p>
+<dl>
+
+<dt><i>reply</i> (QNetworkReply)</dt>
+<dd>
+reference to the reply object
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.__createCPyMenu" ID="CircuitPythonDevice.__createCPyMenu"></a>
+<h4>CircuitPythonDevice.__createCPyMenu</h4>
+<b>__createCPyMenu</b>(<i></i>)
+
+<p>
+        Private method to create the CircuitPython submenu.
+</p>
+<a NAME="CircuitPythonDevice.__deviceVolumeMounted" ID="CircuitPythonDevice.__deviceVolumeMounted"></a>
+<h4>CircuitPythonDevice.__deviceVolumeMounted</h4>
+<b>__deviceVolumeMounted</b>(<i></i>)
+
+<p>
+        Private method to check, if the device volume is mounted.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicated a mounted device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.__findDeviceDirectories" ID="CircuitPythonDevice.__findDeviceDirectories"></a>
+<h4>CircuitPythonDevice.__findDeviceDirectories</h4>
+<b>__findDeviceDirectories</b>(<i>directories</i>)
+
+<p>
+        Private method to find the device directories associated with the
+        current board name.
+</p>
+<dl>
+
+<dt><i>directories</i> (list of str)</dt>
+<dd>
+list of directories to be checked
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of associated directories
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of str
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.__findWorkspace" ID="CircuitPythonDevice.__findWorkspace"></a>
+<h4>CircuitPythonDevice.__findWorkspace</h4>
+<b>__findWorkspace</b>(<i>silent=False</i>)
+
+<p>
+        Private method to find the workspace directory.
+</p>
+<dl>
+
+<dt><i>silent</i> (bool)</dt>
+<dd>
+flag indicating silent operations
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.__flashCircuitPython" ID="CircuitPythonDevice.__flashCircuitPython"></a>
+<h4>CircuitPythonDevice.__flashCircuitPython</h4>
+<b>__flashCircuitPython</b>(<i></i>)
+
+<p>
+        Private slot to flash a CircuitPython firmware to a device supporting UF2.
+</p>
+<a NAME="CircuitPythonDevice.__installLibraryFiles" ID="CircuitPythonDevice.__installLibraryFiles"></a>
+<h4>CircuitPythonDevice.__installLibraryFiles</h4>
+<b>__installLibraryFiles</b>(<i>packageMode=False</i>)
+
+<p>
+        Private slot to install Python files into the onboard library.
+</p>
+<dl>
+
+<dt><i>packageMode</i> (bool (optional))</dt>
+<dd>
+flag indicating to install a library package
+            (defaults to False)
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.__showCircuitPythonVersions" ID="CircuitPythonDevice.__showCircuitPythonVersions"></a>
+<h4>CircuitPythonDevice.__showCircuitPythonVersions</h4>
+<b>__showCircuitPythonVersions</b>(<i></i>)
+
+<p>
+        Private slot to show the CircuitPython version of a connected device and
+        the latest available one (from Github).
+</p>
+<a NAME="CircuitPythonDevice.__showTeensyFlashInstructions" ID="CircuitPythonDevice.__showTeensyFlashInstructions"></a>
+<h4>CircuitPythonDevice.__showTeensyFlashInstructions</h4>
+<b>__showTeensyFlashInstructions</b>(<i></i>)
+
+<p>
+        Private method to show a message box because Teensy does not support
+        the UF2 bootloader yet.
+</p>
+<a NAME="CircuitPythonDevice.__startTeensyLoader" ID="CircuitPythonDevice.__startTeensyLoader"></a>
+<h4>CircuitPythonDevice.__startTeensyLoader</h4>
+<b>__startTeensyLoader</b>(<i></i>)
+
+<p>
+        Private method to start the 'Teensy Loader' application.
+</p>
+<p>
+        Note: The application must be accessible via the application search path.
+</p>
+<a NAME="CircuitPythonDevice.addDeviceMenuEntries" ID="CircuitPythonDevice.addDeviceMenuEntries"></a>
+<h4>CircuitPythonDevice.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.canRunScript" ID="CircuitPythonDevice.canRunScript"></a>
+<h4>CircuitPythonDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.canStartFileManager" ID="CircuitPythonDevice.canStartFileManager"></a>
+<h4>CircuitPythonDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.canStartPlotter" ID="CircuitPythonDevice.canStartPlotter"></a>
+<h4>CircuitPythonDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.canStartRepl" ID="CircuitPythonDevice.canStartRepl"></a>
+<h4>CircuitPythonDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.deviceName" ID="CircuitPythonDevice.deviceName"></a>
+<h4>CircuitPythonDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.forceInterrupt" ID="CircuitPythonDevice.forceInterrupt"></a>
+<h4>CircuitPythonDevice.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.getDocumentationUrl" ID="CircuitPythonDevice.getDocumentationUrl"></a>
+<h4>CircuitPythonDevice.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.getDownloadMenuEntries" ID="CircuitPythonDevice.getDownloadMenuEntries"></a>
+<h4>CircuitPythonDevice.getDownloadMenuEntries</h4>
+<b>getDownloadMenuEntries</b>(<i></i>)
+
+<p>
+        Public method to retrieve the entries for the downloads menu.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of tuples with menu text and URL to be opened for each
+            entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of tuple of (str, str)
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.getWorkspace" ID="CircuitPythonDevice.getWorkspace"></a>
+<h4>CircuitPythonDevice.getWorkspace</h4>
+<b>getWorkspace</b>(<i>silent=False</i>)
+
+<p>
+        Public method to get the workspace directory.
+</p>
+<dl>
+
+<dt><i>silent</i> (bool)</dt>
+<dd>
+flag indicating silent operations
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.hasFlashMenuEntry" ID="CircuitPythonDevice.hasFlashMenuEntry"></a>
+<h4>CircuitPythonDevice.hasFlashMenuEntry</h4>
+<b>hasFlashMenuEntry</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has its own flash menu entry.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a specific flash menu entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.runScript" ID="CircuitPythonDevice.runScript"></a>
+<h4>CircuitPythonDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="CircuitPythonDevice.setButtons" ID="CircuitPythonDevice.setButtons"></a>
+<h4>CircuitPythonDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<a NAME="CircuitPythonDevice.supportsLocalFileAccess" ID="CircuitPythonDevice.supportsLocalFileAccess"></a>
+<h4>CircuitPythonDevice.supportsLocalFileAccess</h4>
+<b>supportsLocalFileAccess</b>(<i></i>)
+
+<p>
+        Public method to indicate file access via a local directory.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating file access via local directory
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+CircuitPythonDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,358 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface</h1>
+
+<p>
+Module implementing an interface to the 'circup' package.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface">CircuitPythonUpdaterInterface</a></td>
+<td>Class implementing an interface to the 'circup' package.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#isCircupAvailable">isCircupAvailable</a></td>
+<td>Function to check for the availability of 'circup'.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="CircuitPythonUpdaterInterface" ID="CircuitPythonUpdaterInterface"></a>
+<h2>CircuitPythonUpdaterInterface</h2>
+
+<p>
+    Class implementing an interface to the 'circup' package.
+</p>
+<h3>Derived from</h3>
+QObject
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__init__">CircuitPythonUpdaterInterface</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__aboutCircup">__aboutCircup</a></td>
+<td>Private slot to show some info about 'circup'.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__addBundle">__addBundle</a></td>
+<td>Private slot to add a bundle to the local bundles list, by "user/repo" github string.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__doUpdateModules">__doUpdateModules</a></td>
+<td>Private method to perform the update of a list of modules.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__generateRequirements">__generateRequirements</a></td>
+<td>Private slot to generate requirements for the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__installFromAvailable">__installFromAvailable</a></td>
+<td>Private slot to install modules onto the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__installFromCode">__installFromCode</a></td>
+<td>Private slot to install modules based on the 'code.py' file of the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__installModules">__installModules</a></td>
+<td>Private method to install the given list of modules.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__installRequirements">__installRequirements</a></td>
+<td>Private slot to install modules determined by a requirements file.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__listOutdatedModules">__listOutdatedModules</a></td>
+<td>Private slot to list the outdated modules of the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__removeBundle">__removeBundle</a></td>
+<td>Private slot to remove one or more bundles from the local bundles list.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__showAvailableModules">__showAvailableModules</a></td>
+<td>Private slot to show the available modules.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__showBundles">__showBundles</a></td>
+<td>Private slot to show the available bundles (default and local).</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__showBundlesModules">__showBundlesModules</a></td>
+<td>Private slot to show the available bundles (default and local) with their modules.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__showInstalledModules">__showInstalledModules</a></td>
+<td>Private slot to show the modules installed on the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__uninstallModules">__uninstallModules</a></td>
+<td>Private slot to uninstall modules from the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__updateAllModules">__updateAllModules</a></td>
+<td>Private slot to update all modules of the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.__updateModules">__updateModules</a></td>
+<td>Private slot to update the modules of the connected device.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.installCircup">installCircup</a></td>
+<td>Public slot to install the 'circup' package via pip.</td>
+</tr>
+<tr>
+<td><a href="#CircuitPythonUpdaterInterface.populateMenu">populateMenu</a></td>
+<td>Public method to populate the 'circup' menu.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="CircuitPythonUpdaterInterface.__init__" ID="CircuitPythonUpdaterInterface.__init__"></a>
+<h4>CircuitPythonUpdaterInterface (Constructor)</h4>
+<b>CircuitPythonUpdaterInterface</b>(<i>device, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>device</i> (CircuitPythonDevice)</dt>
+<dd>
+reference to the CircuitPython device interface
+</dd>
+<dt><i>parent</i> (QObject (optional))</dt>
+<dd>
+reference to the parent object (defaults to None)
+</dd>
+</dl>
+<a NAME="CircuitPythonUpdaterInterface.__aboutCircup" ID="CircuitPythonUpdaterInterface.__aboutCircup"></a>
+<h4>CircuitPythonUpdaterInterface.__aboutCircup</h4>
+<b>__aboutCircup</b>(<i></i>)
+
+<p>
+        Private slot to show some info about 'circup'.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__addBundle" ID="CircuitPythonUpdaterInterface.__addBundle"></a>
+<h4>CircuitPythonUpdaterInterface.__addBundle</h4>
+<b>__addBundle</b>(<i></i>)
+
+<p>
+        Private slot to add a bundle to the local bundles list, by "user/repo" github
+        string.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__doUpdateModules" ID="CircuitPythonUpdaterInterface.__doUpdateModules"></a>
+<h4>CircuitPythonUpdaterInterface.__doUpdateModules</h4>
+<b>__doUpdateModules</b>(<i>modules</i>)
+
+<p>
+        Private method to perform the update of a list of modules.
+</p>
+<dl>
+
+<dt><i>modules</i> (circup.Module)</dt>
+<dd>
+list of modules to be updated
+</dd>
+</dl>
+<a NAME="CircuitPythonUpdaterInterface.__generateRequirements" ID="CircuitPythonUpdaterInterface.__generateRequirements"></a>
+<h4>CircuitPythonUpdaterInterface.__generateRequirements</h4>
+<b>__generateRequirements</b>(<i></i>)
+
+<p>
+        Private slot to generate requirements for the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__installFromAvailable" ID="CircuitPythonUpdaterInterface.__installFromAvailable"></a>
+<h4>CircuitPythonUpdaterInterface.__installFromAvailable</h4>
+<b>__installFromAvailable</b>(<i></i>)
+
+<p>
+        Private slot to install modules onto the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__installFromCode" ID="CircuitPythonUpdaterInterface.__installFromCode"></a>
+<h4>CircuitPythonUpdaterInterface.__installFromCode</h4>
+<b>__installFromCode</b>(<i></i>)
+
+<p>
+        Private slot to install modules based on the 'code.py' file of the
+        connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__installModules" ID="CircuitPythonUpdaterInterface.__installModules"></a>
+<h4>CircuitPythonUpdaterInterface.__installModules</h4>
+<b>__installModules</b>(<i>installs</i>)
+
+<p>
+        Private method to install the given list of modules.
+</p>
+<dl>
+
+<dt><i>installs</i> (list of str)</dt>
+<dd>
+list of module names to be installed
+</dd>
+</dl>
+<a NAME="CircuitPythonUpdaterInterface.__installRequirements" ID="CircuitPythonUpdaterInterface.__installRequirements"></a>
+<h4>CircuitPythonUpdaterInterface.__installRequirements</h4>
+<b>__installRequirements</b>(<i></i>)
+
+<p>
+        Private slot to install modules determined by a requirements file.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__listOutdatedModules" ID="CircuitPythonUpdaterInterface.__listOutdatedModules"></a>
+<h4>CircuitPythonUpdaterInterface.__listOutdatedModules</h4>
+<b>__listOutdatedModules</b>(<i></i>)
+
+<p>
+        Private slot to list the outdated modules of the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__removeBundle" ID="CircuitPythonUpdaterInterface.__removeBundle"></a>
+<h4>CircuitPythonUpdaterInterface.__removeBundle</h4>
+<b>__removeBundle</b>(<i></i>)
+
+<p>
+        Private slot to remove one or more bundles from the local bundles list.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__showAvailableModules" ID="CircuitPythonUpdaterInterface.__showAvailableModules"></a>
+<h4>CircuitPythonUpdaterInterface.__showAvailableModules</h4>
+<b>__showAvailableModules</b>(<i></i>)
+
+<p>
+        Private slot to show the available modules.
+</p>
+<p>
+        These are modules which could be installed on the device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__showBundles" ID="CircuitPythonUpdaterInterface.__showBundles"></a>
+<h4>CircuitPythonUpdaterInterface.__showBundles</h4>
+<b>__showBundles</b>(<i>withModules=False</i>)
+
+<p>
+        Private slot to show the available bundles (default and local).
+</p>
+<dl>
+
+<dt><i>withModules</i> (bool (optional))</dt>
+<dd>
+flag indicating to list the modules and their version
+            (defaults to False)
+</dd>
+</dl>
+<a NAME="CircuitPythonUpdaterInterface.__showBundlesModules" ID="CircuitPythonUpdaterInterface.__showBundlesModules"></a>
+<h4>CircuitPythonUpdaterInterface.__showBundlesModules</h4>
+<b>__showBundlesModules</b>(<i></i>)
+
+<p>
+        Private slot to show the available bundles (default and local) with their
+        modules.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__showInstalledModules" ID="CircuitPythonUpdaterInterface.__showInstalledModules"></a>
+<h4>CircuitPythonUpdaterInterface.__showInstalledModules</h4>
+<b>__showInstalledModules</b>(<i></i>)
+
+<p>
+        Private slot to show the modules installed on the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__uninstallModules" ID="CircuitPythonUpdaterInterface.__uninstallModules"></a>
+<h4>CircuitPythonUpdaterInterface.__uninstallModules</h4>
+<b>__uninstallModules</b>(<i></i>)
+
+<p>
+        Private slot to uninstall modules from the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__updateAllModules" ID="CircuitPythonUpdaterInterface.__updateAllModules"></a>
+<h4>CircuitPythonUpdaterInterface.__updateAllModules</h4>
+<b>__updateAllModules</b>(<i></i>)
+
+<p>
+        Private slot to update all modules of the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.__updateModules" ID="CircuitPythonUpdaterInterface.__updateModules"></a>
+<h4>CircuitPythonUpdaterInterface.__updateModules</h4>
+<b>__updateModules</b>(<i></i>)
+
+<p>
+        Private slot to update the modules of the connected device.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.installCircup" ID="CircuitPythonUpdaterInterface.installCircup"></a>
+<h4>CircuitPythonUpdaterInterface.installCircup</h4>
+<b>installCircup</b>(<i></i>)
+
+<p>
+        Public slot to install the 'circup' package via pip.
+</p>
+<a NAME="CircuitPythonUpdaterInterface.populateMenu" ID="CircuitPythonUpdaterInterface.populateMenu"></a>
+<h4>CircuitPythonUpdaterInterface.populateMenu</h4>
+<b>populateMenu</b>(<i>menu</i>)
+
+<p>
+        Public method to populate the 'circup' menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the menu to be populated
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="isCircupAvailable" ID="isCircupAvailable"></a>
+<h2>isCircupAvailable</h2>
+<b>isCircupAvailable</b>(<i></i>)
+
+<p>
+    Function to check for the availability of 'circup'.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating the availability of 'circup'
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,209 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions</h1>
+
+<p>
+Module implementing variants of some 'circup' functions suitable for 'eric-ide'
+integration.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#ensure_latest_bundle">ensure_latest_bundle</a></td>
+<td>Function to ensure that there's a copy of the latest library bundle available so circup can check the metadata contained therein.</td>
+</tr>
+<tr>
+<td><a href="#find_modules">find_modules</a></td>
+<td>Function to extract metadata from the connected device and available bundles and returns this as a list of Module instances representing the modules on the device.</td>
+</tr>
+<tr>
+<td><a href="#get_circuitpython_version">get_circuitpython_version</a></td>
+<td>Function to return the version number of CircuitPython running on the board connected via ``device_path``, along with the board ID.</td>
+</tr>
+<tr>
+<td><a href="#install_module">install_module</a></td>
+<td>Function to find a connected device and install a given module name.</td>
+</tr>
+<tr>
+<td><a href="#patch_circup">patch_circup</a></td>
+<td>Function to patch 'circup' to use our functions adapted to the use within the eric-ide.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="ensure_latest_bundle" ID="ensure_latest_bundle"></a>
+<h2>ensure_latest_bundle</h2>
+<b>ensure_latest_bundle</b>(<i>bundle</i>)
+
+<p>
+    Function to ensure that there's a copy of the latest library bundle available so
+    circup can check the metadata contained therein.
+</p>
+<dl>
+
+<dt><i>bundle</i> (circup.Bundle)</dt>
+<dd>
+reference to the target Bundle object.
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="find_modules" ID="find_modules"></a>
+<h2>find_modules</h2>
+<b>find_modules</b>(<i>device_path, bundles_list</i>)
+
+<p>
+    Function to extract metadata from the connected device and available bundles and
+    returns this as a list of Module instances representing the modules on the device.
+</p>
+<dl>
+
+<dt><i>device_path</i> (str)</dt>
+<dd>
+path to the connected board
+</dd>
+<dt><i>bundles_list</i> (list of circup.Bundle)</dt>
+<dd>
+list of supported bundles
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of Module instances describing the current state of the
+        modules on the connected device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of circup.Module
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="get_circuitpython_version" ID="get_circuitpython_version"></a>
+<h2>get_circuitpython_version</h2>
+<b>get_circuitpython_version</b>(<i>device_path</i>)
+
+<p>
+    Function to return the version number of CircuitPython running on the board
+    connected via ``device_path``, along with the board ID.
+</p>
+<p>
+    This is obtained from the 'boot_out.txt' file on the device, whose first line
+    will start with something like this:
+</p>
+<p>
+        Adafruit CircuitPython 4.1.0 on 2019-08-02;
+</p>
+<p>
+    While the second line is:
+</p>
+<p>
+        Board ID:raspberry_pi_pico
+</p>
+<dl>
+
+<dt><i>device_path</i> (str)</dt>
+<dd>
+path to the connected board.
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple with the version string for CircuitPython and the board ID string
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (str, str)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="install_module" ID="install_module"></a>
+<h2>install_module</h2>
+<b>install_module</b>(<i>device_path, device_modules, name, py, mod_names</i>)
+
+<p>
+    Function to find a connected device and install a given module name.
+</p>
+<p>
+    Installation is done if it is available in the current module bundle and is not
+    already installed on the device.
+</p>
+<dl>
+
+<dt><i>device_path</i> (str)</dt>
+<dd>
+path to the connected board
+</dd>
+<dt><i>device_modules</i> (list of dict)</dt>
+<dd>
+list of module metadata from the device
+</dd>
+<dt><i>name</i> (str)</dt>
+<dd>
+name of the module to be installed
+</dd>
+<dt><i>py</i> (bool)</dt>
+<dd>
+flag indicating if the module should be installed from source or
+        from a pre-compiled module
+</dd>
+<dt><i>mod_names</i> (dict)</dt>
+<dd>
+dictionary containing metadata from modules that can be generated
+        with circup.get_bundle_versions()
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating success
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="patch_circup" ID="patch_circup"></a>
+<h2>patch_circup</h2>
+<b>patch_circup</b>(<i></i>)
+
+<p>
+    Function to patch 'circup' to use our functions adapted to the use within the
+    eric-ide.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,244 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog</h1>
+
+<p>
+Module implementing a dialog to generate a requirements file.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#RequirementsDialog">RequirementsDialog</a></td>
+<td>Class implementing a dialog to generate a requirements file.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="RequirementsDialog" ID="RequirementsDialog"></a>
+<h2>RequirementsDialog</h2>
+
+<p>
+    Class implementing a dialog to generate a requirements file.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_RequirementsDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#RequirementsDialog.__init__">RequirementsDialog</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.__generateRequirements">__generateRequirements</a></td>
+<td>Private slot to generate the requirements specifiers list.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.__updateButtons">__updateButtons</a></td>
+<td>Private method to set the state of the various buttons.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.__writeToFile">__writeToFile</a></td>
+<td>Private method to write the requirements text to a file.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_buttonBox_clicked">on_buttonBox_clicked</a></td>
+<td>Private slot called by a button of the button box clicked.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_copyButton_clicked">on_copyButton_clicked</a></td>
+<td>Private slot to copy the requirements text to the clipboard.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_insertButton_clicked">on_insertButton_clicked</a></td>
+<td>Private slot to insert the requirements text at the cursor position of the current editor.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_replaceAllButton_clicked">on_replaceAllButton_clicked</a></td>
+<td>Private slot to replace the text of the current editor with the requirements text.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_replaceSelectionButton_clicked">on_replaceSelectionButton_clicked</a></td>
+<td>Private slot to replace the selected text of the current editor with the requirements text.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_requirementsEdit_textChanged">on_requirementsEdit_textChanged</a></td>
+<td>Private slot handling changes of the requirements text.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_requirementsFilePicker_textChanged">on_requirementsFilePicker_textChanged</a></td>
+<td>Private slot handling a change of the requirements file name.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_saveButton_clicked">on_saveButton_clicked</a></td>
+<td>Private slot to save the requirements text to the requirements file.</td>
+</tr>
+<tr>
+<td><a href="#RequirementsDialog.on_saveToButton_clicked">on_saveToButton_clicked</a></td>
+<td>Private slot to write the requirements text to a new file.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="RequirementsDialog.__init__" ID="RequirementsDialog.__init__"></a>
+<h4>RequirementsDialog (Constructor)</h4>
+<b>RequirementsDialog</b>(<i>devicePath, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>devicePath</i> (str)</dt>
+<dd>
+path to the connected board
+</dd>
+<dt><i>parent</i> (QWidget (optional))</dt>
+<dd>
+reference to the parent widget (defaults to None)
+</dd>
+</dl>
+<a NAME="RequirementsDialog.__generateRequirements" ID="RequirementsDialog.__generateRequirements"></a>
+<h4>RequirementsDialog.__generateRequirements</h4>
+<b>__generateRequirements</b>(<i></i>)
+
+<p>
+        Private slot to generate the requirements specifiers list.
+</p>
+<a NAME="RequirementsDialog.__updateButtons" ID="RequirementsDialog.__updateButtons"></a>
+<h4>RequirementsDialog.__updateButtons</h4>
+<b>__updateButtons</b>(<i></i>)
+
+<p>
+        Private method to set the state of the various buttons.
+</p>
+<a NAME="RequirementsDialog.__writeToFile" ID="RequirementsDialog.__writeToFile"></a>
+<h4>RequirementsDialog.__writeToFile</h4>
+<b>__writeToFile</b>(<i>fileName</i>)
+
+<p>
+        Private method to write the requirements text to a file.
+</p>
+<dl>
+
+<dt><i>fileName</i> (str)</dt>
+<dd>
+name of the file to write to
+</dd>
+</dl>
+<a NAME="RequirementsDialog.on_buttonBox_clicked" ID="RequirementsDialog.on_buttonBox_clicked"></a>
+<h4>RequirementsDialog.on_buttonBox_clicked</h4>
+<b>on_buttonBox_clicked</b>(<i>button</i>)
+
+<p>
+        Private slot called by a button of the button box clicked.
+</p>
+<dl>
+
+<dt><i>button</i> (QAbstractButton)</dt>
+<dd>
+button that was clicked
+</dd>
+</dl>
+<a NAME="RequirementsDialog.on_copyButton_clicked" ID="RequirementsDialog.on_copyButton_clicked"></a>
+<h4>RequirementsDialog.on_copyButton_clicked</h4>
+<b>on_copyButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to copy the requirements text to the clipboard.
+</p>
+<a NAME="RequirementsDialog.on_insertButton_clicked" ID="RequirementsDialog.on_insertButton_clicked"></a>
+<h4>RequirementsDialog.on_insertButton_clicked</h4>
+<b>on_insertButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to insert the requirements text at the cursor position
+        of the current editor.
+</p>
+<a NAME="RequirementsDialog.on_replaceAllButton_clicked" ID="RequirementsDialog.on_replaceAllButton_clicked"></a>
+<h4>RequirementsDialog.on_replaceAllButton_clicked</h4>
+<b>on_replaceAllButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to replace the text of the current editor with the
+        requirements text.
+</p>
+<a NAME="RequirementsDialog.on_replaceSelectionButton_clicked" ID="RequirementsDialog.on_replaceSelectionButton_clicked"></a>
+<h4>RequirementsDialog.on_replaceSelectionButton_clicked</h4>
+<b>on_replaceSelectionButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to replace the selected text of the current editor
+        with the requirements text.
+</p>
+<a NAME="RequirementsDialog.on_requirementsEdit_textChanged" ID="RequirementsDialog.on_requirementsEdit_textChanged"></a>
+<h4>RequirementsDialog.on_requirementsEdit_textChanged</h4>
+<b>on_requirementsEdit_textChanged</b>(<i></i>)
+
+<p>
+        Private slot handling changes of the requirements text.
+</p>
+<a NAME="RequirementsDialog.on_requirementsFilePicker_textChanged" ID="RequirementsDialog.on_requirementsFilePicker_textChanged"></a>
+<h4>RequirementsDialog.on_requirementsFilePicker_textChanged</h4>
+<b>on_requirementsFilePicker_textChanged</b>(<i>txt</i>)
+
+<p>
+        Private slot handling a change of the requirements file name.
+</p>
+<dl>
+
+<dt><i>txt</i> (str)</dt>
+<dd>
+name of the requirements file
+</dd>
+</dl>
+<a NAME="RequirementsDialog.on_saveButton_clicked" ID="RequirementsDialog.on_saveButton_clicked"></a>
+<h4>RequirementsDialog.on_saveButton_clicked</h4>
+<b>on_saveButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to save the requirements text to the requirements file.
+</p>
+<a NAME="RequirementsDialog.on_saveToButton_clicked" ID="RequirementsDialog.on_saveToButton_clicked"></a>
+<h4>RequirementsDialog.on_saveToButton_clicked</h4>
+<b>on_saveToButton_clicked</b>(<i></i>)
+
+<p>
+        Private slot to write the requirements text to a new file.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog</h1>
+
+<p>
+Module implementing a dialog showing the available bundles and their modules.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#ShowBundlesDialog">ShowBundlesDialog</a></td>
+<td>Class implementing a dialog showing the available bundles and their modules.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="ShowBundlesDialog" ID="ShowBundlesDialog"></a>
+<h2>ShowBundlesDialog</h2>
+
+<p>
+    Class implementing a dialog showing the available bundles and their modules.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_ShowBundlesDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#ShowBundlesDialog.__init__">ShowBundlesDialog</a></td>
+<td>Constructor</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="ShowBundlesDialog.__init__" ID="ShowBundlesDialog.__init__"></a>
+<h4>ShowBundlesDialog (Constructor)</h4>
+<b>ShowBundlesDialog</b>(<i>withModules, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>withModules</i> (bool)</dt>
+<dd>
+flag indicating to list the modules and their version
+</dd>
+<dt><i>parent</i> (QWidget (optional))</dt>
+<dd>
+reference to the parent widget (defaults to None)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog</h1>
+
+<p>
+Module implementing a dialog to show the modules installed on the connected device.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#ShowInstalledDialog">ShowInstalledDialog</a></td>
+<td>Class implementing a dialog to show the modules installed on the connected device.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="ShowInstalledDialog" ID="ShowInstalledDialog"></a>
+<h2>ShowInstalledDialog</h2>
+
+<p>
+    Class implementing a dialog to show the modules installed on the connected device.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_ShowInstalledDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#ShowInstalledDialog.__init__">ShowInstalledDialog</a></td>
+<td>Constructor</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="ShowInstalledDialog.__init__" ID="ShowInstalledDialog.__init__"></a>
+<h4>ShowInstalledDialog (Constructor)</h4>
+<b>ShowInstalledDialog</b>(<i>devicePath, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>devicePath</i> (str)</dt>
+<dd>
+path to the connected board
+</dd>
+<dt><i>parent</i> (QWidget (optional))</dt>
+<dd>
+reference to the parent widget (defaults to None)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,149 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog</h1>
+
+<p>
+Module implementing a dialog to show outdated modules of a connected device.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#ShowOutdatedDialog">ShowOutdatedDialog</a></td>
+<td>Class implementing a dialog to show outdated modules of a connected device.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="ShowOutdatedDialog" ID="ShowOutdatedDialog"></a>
+<h2>ShowOutdatedDialog</h2>
+
+<p>
+    Class implementing a dialog to show outdated modules of a connected device.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_ShowOutdatedDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#ShowOutdatedDialog.__init__">ShowOutdatedDialog</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#ShowOutdatedDialog.__checkCountUpdated">__checkCountUpdated</a></td>
+<td>Private method to handle an update of the check count.</td>
+</tr>
+<tr>
+<td><a href="#ShowOutdatedDialog.getSelection">getSelection</a></td>
+<td>Public method to get the list of selected modules.</td>
+</tr>
+<tr>
+<td><a href="#ShowOutdatedDialog.on_modulesList_itemChanged">on_modulesList_itemChanged</a></td>
+<td>Private slot to handle a change of the check state of an item.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="ShowOutdatedDialog.__init__" ID="ShowOutdatedDialog.__init__"></a>
+<h4>ShowOutdatedDialog (Constructor)</h4>
+<b>ShowOutdatedDialog</b>(<i>devicePath, selectionMode=False, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>devicePath</i> (str)</dt>
+<dd>
+path to the connected board
+</dd>
+<dt><i>selectionMode</i> (bool (optional))</dt>
+<dd>
+flag indicating the activation of the selection mode
+            (defaults to False)
+</dd>
+<dt><i>parent</i> (QWidget (optional))</dt>
+<dd>
+reference to the parent widget (defaults to None)
+</dd>
+</dl>
+<a NAME="ShowOutdatedDialog.__checkCountUpdated" ID="ShowOutdatedDialog.__checkCountUpdated"></a>
+<h4>ShowOutdatedDialog.__checkCountUpdated</h4>
+<b>__checkCountUpdated</b>(<i></i>)
+
+<p>
+        Private method to handle an update of the check count.
+</p>
+<a NAME="ShowOutdatedDialog.getSelection" ID="ShowOutdatedDialog.getSelection"></a>
+<h4>ShowOutdatedDialog.getSelection</h4>
+<b>getSelection</b>(<i></i>)
+
+<p>
+        Public method to get the list of selected modules.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of selected modules
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+circup.Module
+</dd>
+</dl>
+<a NAME="ShowOutdatedDialog.on_modulesList_itemChanged" ID="ShowOutdatedDialog.on_modulesList_itemChanged"></a>
+<h4>ShowOutdatedDialog.on_modulesList_itemChanged</h4>
+<b>on_modulesList_itemChanged</b>(<i>item, column</i>)
+
+<p>
+        Private slot to handle a change of the check state of an item.
+</p>
+<dl>
+
+<dt><i>item</i> (QTreeWidgetItem)</dt>
+<dd>
+reference to the changed item
+</dd>
+<dt><i>column</i> (int)</dt>
+<dd>
+changed column
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.DeviceBase.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,713 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.DeviceBase</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.DeviceBase</h1>
+
+<p>
+Module implementing some utility functions and the MicroPythonDevice base
+class.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#BaseDevice">BaseDevice</a></td>
+<td>Base class for the more specific MicroPython devices.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="BaseDevice" ID="BaseDevice"></a>
+<h2>BaseDevice</h2>
+
+<p>
+    Base class for the more specific MicroPython devices.
+</p>
+<h3>Derived from</h3>
+QObject
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#BaseDevice.__init__">BaseDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.checkDeviceData">checkDeviceData</a></td>
+<td>Public method to check the validity of the device data determined during connecting the device.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.downloadFirmware">downloadFirmware</a></td>
+<td>Public method to download the device firmware.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.getDeviceData">getDeviceData</a></td>
+<td>Public method to get a copy of the determined device data.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.getDeviceType">getDeviceType</a></td>
+<td>Public method to get the device type.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
+<td>Public method to retrieve the entries for the downloads menu.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.getFirmwareUrl">getFirmwareUrl</a></td>
+<td>Public method to get the device firmware download URL.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.getWorkspace">getWorkspace</a></td>
+<td>Public method to get the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.handleDataFlood">handleDataFlood</a></td>
+<td>Public slot handling a data floof from the device.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.hasDocumentationUrl">hasDocumentationUrl</a></td>
+<td>Public method to check, if the device has a configured documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.hasFirmwareUrl">hasFirmwareUrl</a></td>
+<td>Public method to check, if the device has a configured firmware download URL.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
+<td>Public method to check, if the device has its own flash menu entry.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.hasTimeCommands">hasTimeCommands</a></td>
+<td>Public method to check, if the device supports time commands.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.selectDeviceDirectory">selectDeviceDirectory</a></td>
+<td>Public method to select the device directory from a list of detected ones.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.sendCommands">sendCommands</a></td>
+<td>Public method to send a list of commands to the device.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.setConnected">setConnected</a></td>
+<td>Public method to set the connection state.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.setFileManager">setFileManager</a></td>
+<td>Public method to set the File Manager status and dependent status.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.setPlotter">setPlotter</a></td>
+<td>Public method to set the Plotter status and dependent status.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.setRepl">setRepl</a></td>
+<td>Public method to set the REPL status and dependent status.</td>
+</tr>
+<tr>
+<td><a href="#BaseDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
+<td>Public method to indicate file access via a local directory.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="BaseDevice.__init__" ID="BaseDevice.__init__"></a>
+<h4>BaseDevice (Constructor)</h4>
+<b>BaseDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="BaseDevice.addDeviceMenuEntries" ID="BaseDevice.addDeviceMenuEntries"></a>
+<h4>BaseDevice.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="BaseDevice.canRunScript" ID="BaseDevice.canRunScript"></a>
+<h4>BaseDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="BaseDevice.canStartFileManager" ID="BaseDevice.canStartFileManager"></a>
+<h4>BaseDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="BaseDevice.canStartPlotter" ID="BaseDevice.canStartPlotter"></a>
+<h4>BaseDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="BaseDevice.canStartRepl" ID="BaseDevice.canStartRepl"></a>
+<h4>BaseDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="BaseDevice.checkDeviceData" ID="BaseDevice.checkDeviceData"></a>
+<h4>BaseDevice.checkDeviceData</h4>
+<b>checkDeviceData</b>(<i></i>)
+
+<p>
+        Public method to check the validity of the device data determined during
+        connecting the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating valid device data
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="BaseDevice.deviceName" ID="BaseDevice.deviceName"></a>
+<h4>BaseDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="BaseDevice.downloadFirmware" ID="BaseDevice.downloadFirmware"></a>
+<h4>BaseDevice.downloadFirmware</h4>
+<b>downloadFirmware</b>(<i></i>)
+
+<p>
+        Public method to download the device firmware.
+</p>
+<a NAME="BaseDevice.forceInterrupt" ID="BaseDevice.forceInterrupt"></a>
+<h4>BaseDevice.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="BaseDevice.getDeviceData" ID="BaseDevice.getDeviceData"></a>
+<h4>BaseDevice.getDeviceData</h4>
+<b>getDeviceData</b>(<i></i>)
+
+<p>
+        Public method to get a copy of the determined device data.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+dictionary containing the essential device data
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+dict
+</dd>
+</dl>
+<a NAME="BaseDevice.getDeviceType" ID="BaseDevice.getDeviceType"></a>
+<h4>BaseDevice.getDeviceType</h4>
+<b>getDeviceType</b>(<i></i>)
+
+<p>
+        Public method to get the device type.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+type of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="BaseDevice.getDocumentationUrl" ID="BaseDevice.getDocumentationUrl"></a>
+<h4>BaseDevice.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="BaseDevice.getDownloadMenuEntries" ID="BaseDevice.getDownloadMenuEntries"></a>
+<h4>BaseDevice.getDownloadMenuEntries</h4>
+<b>getDownloadMenuEntries</b>(<i></i>)
+
+<p>
+        Public method to retrieve the entries for the downloads menu.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of tuples with menu text and URL to be opened for each
+            entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of tuple of (str, str)
+</dd>
+</dl>
+<a NAME="BaseDevice.getFirmwareUrl" ID="BaseDevice.getFirmwareUrl"></a>
+<h4>BaseDevice.getFirmwareUrl</h4>
+<b>getFirmwareUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device firmware download URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+firmware download URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="BaseDevice.getWorkspace" ID="BaseDevice.getWorkspace"></a>
+<h4>BaseDevice.getWorkspace</h4>
+<b>getWorkspace</b>(<i></i>)
+
+<p>
+        Public method to get the workspace directory.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="BaseDevice.handleDataFlood" ID="BaseDevice.handleDataFlood"></a>
+<h4>BaseDevice.handleDataFlood</h4>
+<b>handleDataFlood</b>(<i></i>)
+
+<p>
+        Public slot handling a data floof from the device.
+</p>
+<a NAME="BaseDevice.hasDocumentationUrl" ID="BaseDevice.hasDocumentationUrl"></a>
+<h4>BaseDevice.hasDocumentationUrl</h4>
+<b>hasDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has a configured documentation
+        URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a configured documentation URL
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="BaseDevice.hasFirmwareUrl" ID="BaseDevice.hasFirmwareUrl"></a>
+<h4>BaseDevice.hasFirmwareUrl</h4>
+<b>hasFirmwareUrl</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has a configured firmware
+        download URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a configured firmware download URL
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="BaseDevice.hasFlashMenuEntry" ID="BaseDevice.hasFlashMenuEntry"></a>
+<h4>BaseDevice.hasFlashMenuEntry</h4>
+<b>hasFlashMenuEntry</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has its own flash menu entry.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a specific flash menu entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="BaseDevice.hasTimeCommands" ID="BaseDevice.hasTimeCommands"></a>
+<h4>BaseDevice.hasTimeCommands</h4>
+<b>hasTimeCommands</b>(<i></i>)
+
+<p>
+        Public method to check, if the device supports time commands.
+</p>
+<p>
+        The default returns True.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating support for time commands
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="BaseDevice.runScript" ID="BaseDevice.runScript"></a>
+<h4>BaseDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="BaseDevice.selectDeviceDirectory" ID="BaseDevice.selectDeviceDirectory"></a>
+<h4>BaseDevice.selectDeviceDirectory</h4>
+<b>selectDeviceDirectory</b>(<i>deviceDirectories</i>)
+
+<p>
+        Public method to select the device directory from a list of detected
+        ones.
+</p>
+<dl>
+
+<dt><i>deviceDirectories</i> (list of str)</dt>
+<dd>
+list of directories to select from
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+selected directory or an empty string
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="BaseDevice.sendCommands" ID="BaseDevice.sendCommands"></a>
+<h4>BaseDevice.sendCommands</h4>
+<b>sendCommands</b>(<i>commandsList</i>)
+
+<p>
+        Public method to send a list of commands to the device.
+</p>
+<dl>
+
+<dt><i>commandsList</i> (list of str)</dt>
+<dd>
+list of commands to be sent to the device
+</dd>
+</dl>
+<a NAME="BaseDevice.setButtons" ID="BaseDevice.setButtons"></a>
+<h4>BaseDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<a NAME="BaseDevice.setConnected" ID="BaseDevice.setConnected"></a>
+<h4>BaseDevice.setConnected</h4>
+<b>setConnected</b>(<i>connected</i>)
+
+<p>
+        Public method to set the connection state.
+</p>
+<p>
+        Note: This method can be overwritten to perform actions upon connect
+        or disconnect of the device.
+</p>
+<dl>
+
+<dt><i>connected</i> (bool)</dt>
+<dd>
+connection state
+</dd>
+</dl>
+<a NAME="BaseDevice.setFileManager" ID="BaseDevice.setFileManager"></a>
+<h4>BaseDevice.setFileManager</h4>
+<b>setFileManager</b>(<i>on</i>)
+
+<p>
+        Public method to set the File Manager status and dependent status.
+</p>
+<dl>
+
+<dt><i>on</i> (bool)</dt>
+<dd>
+flag indicating the active status
+</dd>
+</dl>
+<a NAME="BaseDevice.setPlotter" ID="BaseDevice.setPlotter"></a>
+<h4>BaseDevice.setPlotter</h4>
+<b>setPlotter</b>(<i>on</i>)
+
+<p>
+        Public method to set the Plotter status and dependent status.
+</p>
+<dl>
+
+<dt><i>on</i> (bool)</dt>
+<dd>
+flag indicating the active status
+</dd>
+</dl>
+<a NAME="BaseDevice.setRepl" ID="BaseDevice.setRepl"></a>
+<h4>BaseDevice.setRepl</h4>
+<b>setRepl</b>(<i>on</i>)
+
+<p>
+        Public method to set the REPL status and dependent status.
+</p>
+<dl>
+
+<dt><i>on</i> (bool)</dt>
+<dd>
+flag indicating the active status
+</dd>
+</dl>
+<a NAME="BaseDevice.supportsLocalFileAccess" ID="BaseDevice.supportsLocalFileAccess"></a>
+<h4>BaseDevice.supportsLocalFileAccess</h4>
+<b>supportsLocalFileAccess</b>(<i></i>)
+
+<p>
+        Public method to indicate file access via a local directory.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating file access via local directory
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.EspDevices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,556 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.EspDevices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.EspDevices</h1>
+
+<p>
+Module implementing the device interface class for ESP32 and ESP8266 based
+boards.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#EspDevice">EspDevice</a></td>
+<td>Class implementing the device for ESP32 and ESP8266 based boards.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="EspDevice" ID="EspDevice"></a>
+<h2>EspDevice</h2>
+
+<p>
+    Class implementing the device for ESP32 and ESP8266 based boards.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#EspDevice.__init__">EspDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__backupFlash">__backupFlash</a></td>
+<td>Private slot to backup the currently flashed firmware.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__createEsp32Submenu">__createEsp32Submenu</a></td>
+<td>Private method to create the ESP32 submenu.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__eraseFlash">__eraseFlash</a></td>
+<td>Private slot to erase the device flash memory.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
+<td>Private method handling the response of the latest version request.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__flashAddons">__flashAddons</a></td>
+<td>Private slot to flash some additional firmware images.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__flashMicroPython">__flashMicroPython</a></td>
+<td>Private slot to flash a MicroPython firmware to the device.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__installEspTool">__installEspTool</a></td>
+<td>Private slot to install the esptool package via pip.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__resetDevice">__resetDevice</a></td>
+<td>Private slot to reset the connected device.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__restoreFlash">__restoreFlash</a></td>
+<td>Private slot to restore a previously saved firmware.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__showChipID">__showChipID</a></td>
+<td>Private slot to show the ID of the ESP chip.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
+<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__showFlashID">__showFlashID</a></td>
+<td>Private slot to show the ID of the ESP flash chip.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.__showMACAddress">__showMACAddress</a></td>
+<td>Private slot to show the MAC address of the ESP chip.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.getFirmwareUrl">getFirmwareUrl</a></td>
+<td>Public method to get the device firmware download URL.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
+<td>Public method to check, if the device has its own flash menu entry.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#EspDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="EspDevice.__init__" ID="EspDevice.__init__"></a>
+<h4>EspDevice (Constructor)</h4>
+<b>EspDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="EspDevice.__backupFlash" ID="EspDevice.__backupFlash"></a>
+<h4>EspDevice.__backupFlash</h4>
+<b>__backupFlash</b>(<i></i>)
+
+<p>
+        Private slot to backup the currently flashed firmware.
+</p>
+<a NAME="EspDevice.__createEsp32Submenu" ID="EspDevice.__createEsp32Submenu"></a>
+<h4>EspDevice.__createEsp32Submenu</h4>
+<b>__createEsp32Submenu</b>(<i></i>)
+
+<p>
+        Private method to create the ESP32 submenu.
+</p>
+<a NAME="EspDevice.__eraseFlash" ID="EspDevice.__eraseFlash"></a>
+<h4>EspDevice.__eraseFlash</h4>
+<b>__eraseFlash</b>(<i></i>)
+
+<p>
+        Private slot to erase the device flash memory.
+</p>
+<a NAME="EspDevice.__firmwareVersionResponse" ID="EspDevice.__firmwareVersionResponse"></a>
+<h4>EspDevice.__firmwareVersionResponse</h4>
+<b>__firmwareVersionResponse</b>(<i>reply</i>)
+
+<p>
+        Private method handling the response of the latest version request.
+</p>
+<dl>
+
+<dt><i>reply</i> (QNetworkReply)</dt>
+<dd>
+reference to the reply object
+</dd>
+</dl>
+<a NAME="EspDevice.__flashAddons" ID="EspDevice.__flashAddons"></a>
+<h4>EspDevice.__flashAddons</h4>
+<b>__flashAddons</b>(<i></i>)
+
+<p>
+        Private slot to flash some additional firmware images.
+</p>
+<a NAME="EspDevice.__flashMicroPython" ID="EspDevice.__flashMicroPython"></a>
+<h4>EspDevice.__flashMicroPython</h4>
+<b>__flashMicroPython</b>(<i></i>)
+
+<p>
+        Private slot to flash a MicroPython firmware to the device.
+</p>
+<a NAME="EspDevice.__installEspTool" ID="EspDevice.__installEspTool"></a>
+<h4>EspDevice.__installEspTool</h4>
+<b>__installEspTool</b>(<i></i>)
+
+<p>
+        Private slot to install the esptool package via pip.
+</p>
+<a NAME="EspDevice.__resetDevice" ID="EspDevice.__resetDevice"></a>
+<h4>EspDevice.__resetDevice</h4>
+<b>__resetDevice</b>(<i></i>)
+
+<p>
+        Private slot to reset the connected device.
+</p>
+<a NAME="EspDevice.__restoreFlash" ID="EspDevice.__restoreFlash"></a>
+<h4>EspDevice.__restoreFlash</h4>
+<b>__restoreFlash</b>(<i></i>)
+
+<p>
+        Private slot to restore a previously saved firmware.
+</p>
+<a NAME="EspDevice.__showChipID" ID="EspDevice.__showChipID"></a>
+<h4>EspDevice.__showChipID</h4>
+<b>__showChipID</b>(<i></i>)
+
+<p>
+        Private slot to show the ID of the ESP chip.
+</p>
+<a NAME="EspDevice.__showFirmwareVersions" ID="EspDevice.__showFirmwareVersions"></a>
+<h4>EspDevice.__showFirmwareVersions</h4>
+<b>__showFirmwareVersions</b>(<i></i>)
+
+<p>
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+</p>
+<a NAME="EspDevice.__showFlashID" ID="EspDevice.__showFlashID"></a>
+<h4>EspDevice.__showFlashID</h4>
+<b>__showFlashID</b>(<i></i>)
+
+<p>
+        Private slot to show the ID of the ESP flash chip.
+</p>
+<a NAME="EspDevice.__showMACAddress" ID="EspDevice.__showMACAddress"></a>
+<h4>EspDevice.__showMACAddress</h4>
+<b>__showMACAddress</b>(<i></i>)
+
+<p>
+        Private slot to show the MAC address of the ESP chip.
+</p>
+<a NAME="EspDevice.addDeviceMenuEntries" ID="EspDevice.addDeviceMenuEntries"></a>
+<h4>EspDevice.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="EspDevice.canRunScript" ID="EspDevice.canRunScript"></a>
+<h4>EspDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="EspDevice.canStartFileManager" ID="EspDevice.canStartFileManager"></a>
+<h4>EspDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="EspDevice.canStartPlotter" ID="EspDevice.canStartPlotter"></a>
+<h4>EspDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="EspDevice.canStartRepl" ID="EspDevice.canStartRepl"></a>
+<h4>EspDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="EspDevice.deviceName" ID="EspDevice.deviceName"></a>
+<h4>EspDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="EspDevice.forceInterrupt" ID="EspDevice.forceInterrupt"></a>
+<h4>EspDevice.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="EspDevice.getDocumentationUrl" ID="EspDevice.getDocumentationUrl"></a>
+<h4>EspDevice.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="EspDevice.getFirmwareUrl" ID="EspDevice.getFirmwareUrl"></a>
+<h4>EspDevice.getFirmwareUrl</h4>
+<b>getFirmwareUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device firmware download URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+firmware download URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="EspDevice.hasFlashMenuEntry" ID="EspDevice.hasFlashMenuEntry"></a>
+<h4>EspDevice.hasFlashMenuEntry</h4>
+<b>hasFlashMenuEntry</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has its own flash menu entry.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a specific flash menu entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="EspDevice.runScript" ID="EspDevice.runScript"></a>
+<h4>EspDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="EspDevice.setButtons" ID="EspDevice.setButtons"></a>
+<h4>EspDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+EspDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog</h1>
+
+<p>
+Module implementing a dialog to select the ESP chip type and the backup and
+restore parameters.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog">EspBackupRestoreFirmwareDialog</a></td>
+<td>Class implementing a dialog to select the ESP chip type and the backup and restore parameters.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="EspBackupRestoreFirmwareDialog" ID="EspBackupRestoreFirmwareDialog"></a>
+<h2>EspBackupRestoreFirmwareDialog</h2>
+
+<p>
+    Class implementing a dialog to select the ESP chip type and the backup and
+    restore parameters.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_EspBackupRestoreFirmwareDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>Chips</td></tr><tr><td>FlashModes</td></tr><tr><td>FlashSizes</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog.__init__">EspBackupRestoreFirmwareDialog</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog.__updateOkButton">__updateOkButton</a></td>
+<td>Private method to update the state of the OK button.</td>
+</tr>
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog.getData">getData</a></td>
+<td>Public method to get the entered data.</td>
+</tr>
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged">on_espComboBox_currentTextChanged</a></td>
+<td>Private slot to handle the selection of a chip type.</td>
+</tr>
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged">on_firmwarePicker_textChanged</a></td>
+<td>Private slot handling a change of the firmware path.</td>
+</tr>
+<tr>
+<td><a href="#EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged">on_sizeComboBox_currentTextChanged</a></td>
+<td>Private slot handling a change of the selected firmware size.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="EspBackupRestoreFirmwareDialog.__init__" ID="EspBackupRestoreFirmwareDialog.__init__"></a>
+<h4>EspBackupRestoreFirmwareDialog (Constructor)</h4>
+<b>EspBackupRestoreFirmwareDialog</b>(<i>backupMode=True, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>backupMode</i> (bool)</dt>
+<dd>
+flag indicating parameters for a firmware backup are
+            requested
+</dd>
+<dt><i>parent</i> (QWidget)</dt>
+<dd>
+reference to the parent widget
+</dd>
+</dl>
+<a NAME="EspBackupRestoreFirmwareDialog.__updateOkButton" ID="EspBackupRestoreFirmwareDialog.__updateOkButton"></a>
+<h4>EspBackupRestoreFirmwareDialog.__updateOkButton</h4>
+<b>__updateOkButton</b>(<i></i>)
+
+<p>
+        Private method to update the state of the OK button.
+</p>
+<a NAME="EspBackupRestoreFirmwareDialog.getData" ID="EspBackupRestoreFirmwareDialog.getData"></a>
+<h4>EspBackupRestoreFirmwareDialog.getData</h4>
+<b>getData</b>(<i></i>)
+
+<p>
+        Public method to get the entered data.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing the selected chip type, the firmware size,
+            the baud rate or flashing, the flash mode and the path of the
+            firmware file
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (str, str, str, str, str)
+</dd>
+</dl>
+<a NAME="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" ID="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged"></a>
+<h4>EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged</h4>
+<b>on_espComboBox_currentTextChanged</b>(<i>chip</i>)
+
+<p>
+        Private slot to handle the selection of a chip type.
+</p>
+<dl>
+
+<dt><i>chip</i> (str)</dt>
+<dd>
+selected chip type
+</dd>
+</dl>
+<a NAME="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" ID="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged"></a>
+<h4>EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged</h4>
+<b>on_firmwarePicker_textChanged</b>(<i>firmware</i>)
+
+<p>
+        Private slot handling a change of the firmware path.
+</p>
+<dl>
+
+<dt><i>firmware</i> (str)</dt>
+<dd>
+path to the firmware
+</dd>
+</dl>
+<a NAME="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" ID="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged"></a>
+<h4>EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged</h4>
+<b>on_sizeComboBox_currentTextChanged</b>(<i>size</i>)
+
+<p>
+        Private slot handling a change of the selected firmware size.
+</p>
+<dl>
+
+<dt><i>size</i> (str)</dt>
+<dd>
+selected size text
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog</h1>
+
+<p>
+Module implementing a dialog to select the ESP chip type and the firmware to
+be flashed.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#EspFirmwareSelectionDialog">EspFirmwareSelectionDialog</a></td>
+<td>Class implementing a dialog to select the ESP chip type and the firmware to be flashed.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<hr />
+<hr />
+<a NAME="EspFirmwareSelectionDialog" ID="EspFirmwareSelectionDialog"></a>
+<h2>EspFirmwareSelectionDialog</h2>
+
+<p>
+    Class implementing a dialog to select the ESP chip type and the firmware to
+    be flashed.
+</p>
+<h3>Derived from</h3>
+QDialog, Ui_EspFirmwareSelectionDialog
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>Chips</td></tr><tr><td>FlashAddresses</td></tr><tr><td>FlashModes</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#EspFirmwareSelectionDialog.__init__">EspFirmwareSelectionDialog</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#EspFirmwareSelectionDialog.__updateOkButton">__updateOkButton</a></td>
+<td>Private method to update the state of the OK button.</td>
+</tr>
+<tr>
+<td><a href="#EspFirmwareSelectionDialog.getData">getData</a></td>
+<td>Public method to get the entered data.</td>
+</tr>
+<tr>
+<td><a href="#EspFirmwareSelectionDialog.on_addressEdit_textChanged">on_addressEdit_textChanged</a></td>
+<td>Private slot handling a change of the address.</td>
+</tr>
+<tr>
+<td><a href="#EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged">on_espComboBox_currentTextChanged</a></td>
+<td>Private slot to handle the selection of a chip type.</td>
+</tr>
+<tr>
+<td><a href="#EspFirmwareSelectionDialog.on_firmwarePicker_textChanged">on_firmwarePicker_textChanged</a></td>
+<td>Private slot handling a change of the firmware path.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="EspFirmwareSelectionDialog.__init__" ID="EspFirmwareSelectionDialog.__init__"></a>
+<h4>EspFirmwareSelectionDialog (Constructor)</h4>
+<b>EspFirmwareSelectionDialog</b>(<i>addon=False, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>addon</i> (bool)</dt>
+<dd>
+flag indicating an addon firmware
+</dd>
+<dt><i>parent</i> (QWidget)</dt>
+<dd>
+reference to the parent widget
+</dd>
+</dl>
+<a NAME="EspFirmwareSelectionDialog.__updateOkButton" ID="EspFirmwareSelectionDialog.__updateOkButton"></a>
+<h4>EspFirmwareSelectionDialog.__updateOkButton</h4>
+<b>__updateOkButton</b>(<i></i>)
+
+<p>
+        Private method to update the state of the OK button.
+</p>
+<a NAME="EspFirmwareSelectionDialog.getData" ID="EspFirmwareSelectionDialog.getData"></a>
+<h4>EspFirmwareSelectionDialog.getData</h4>
+<b>getData</b>(<i></i>)
+
+<p>
+        Public method to get the entered data.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing the selected chip type, the path of the
+            firmware file, the baud rate, the flash mode and the flash
+            address
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (str, str, str, str, str)
+</dd>
+</dl>
+<a NAME="EspFirmwareSelectionDialog.on_addressEdit_textChanged" ID="EspFirmwareSelectionDialog.on_addressEdit_textChanged"></a>
+<h4>EspFirmwareSelectionDialog.on_addressEdit_textChanged</h4>
+<b>on_addressEdit_textChanged</b>(<i>address</i>)
+
+<p>
+        Private slot handling a change of the address.
+</p>
+<dl>
+
+<dt><i>address</i> (str)</dt>
+<dd>
+entered address
+</dd>
+</dl>
+<a NAME="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" ID="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged"></a>
+<h4>EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged</h4>
+<b>on_espComboBox_currentTextChanged</b>(<i>chip</i>)
+
+<p>
+        Private slot to handle the selection of a chip type.
+</p>
+<dl>
+
+<dt><i>chip</i> (str)</dt>
+<dd>
+selected chip type
+</dd>
+</dl>
+<a NAME="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" ID="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged"></a>
+<h4>EspFirmwareSelectionDialog.on_firmwarePicker_textChanged</h4>
+<b>on_firmwarePicker_textChanged</b>(<i>firmware</i>)
+
+<p>
+        Private slot handling a change of the firmware path.
+</p>
+<dl>
+
+<dt><i>firmware</i> (str)</dt>
+<dd>
+path to the firmware
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.GenericMicroPythonDevices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,408 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.GenericMicroPythonDevices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.GenericMicroPythonDevices</h1>
+
+<p>
+Module implementing the device interface class for generic MicroPython devices
+(i.e. those devices not specifically supported yet).
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#GenericMicroPythonDevice">GenericMicroPythonDevice</a></td>
+<td>Class implementing the device interface for generic MicroPython boards.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="GenericMicroPythonDevice" ID="GenericMicroPythonDevice"></a>
+<h2>GenericMicroPythonDevice</h2>
+
+<p>
+    Class implementing the device interface for generic MicroPython boards.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#GenericMicroPythonDevice.__init__">GenericMicroPythonDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td>
+<td>Private method to check, if the device volume is mounted.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.__findWorkspace">__findWorkspace</a></td>
+<td>Private method to find the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.getWorkspace">getWorkspace</a></td>
+<td>Public method to get the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+<tr>
+<td><a href="#GenericMicroPythonDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
+<td>Public method to indicate file access via a local directory.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="GenericMicroPythonDevice.__init__" ID="GenericMicroPythonDevice.__init__"></a>
+<h4>GenericMicroPythonDevice (Constructor)</h4>
+<b>GenericMicroPythonDevice</b>(<i>microPythonWidget, deviceType, vid, pid, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.__deviceVolumeMounted" ID="GenericMicroPythonDevice.__deviceVolumeMounted"></a>
+<h4>GenericMicroPythonDevice.__deviceVolumeMounted</h4>
+<b>__deviceVolumeMounted</b>(<i></i>)
+
+<p>
+        Private method to check, if the device volume is mounted.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicated a mounted device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.__findWorkspace" ID="GenericMicroPythonDevice.__findWorkspace"></a>
+<h4>GenericMicroPythonDevice.__findWorkspace</h4>
+<b>__findWorkspace</b>(<i>silent=False</i>)
+
+<p>
+        Private method to find the workspace directory.
+</p>
+<dl>
+
+<dt><i>silent</i> (bool)</dt>
+<dd>
+flag indicating silent operations
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.canRunScript" ID="GenericMicroPythonDevice.canRunScript"></a>
+<h4>GenericMicroPythonDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.canStartFileManager" ID="GenericMicroPythonDevice.canStartFileManager"></a>
+<h4>GenericMicroPythonDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.canStartPlotter" ID="GenericMicroPythonDevice.canStartPlotter"></a>
+<h4>GenericMicroPythonDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.canStartRepl" ID="GenericMicroPythonDevice.canStartRepl"></a>
+<h4>GenericMicroPythonDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.deviceName" ID="GenericMicroPythonDevice.deviceName"></a>
+<h4>GenericMicroPythonDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.getWorkspace" ID="GenericMicroPythonDevice.getWorkspace"></a>
+<h4>GenericMicroPythonDevice.getWorkspace</h4>
+<b>getWorkspace</b>(<i>silent=False</i>)
+
+<p>
+        Public method to get the workspace directory.
+</p>
+<dl>
+
+<dt><i>silent</i> (bool)</dt>
+<dd>
+flag indicating silent operations
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.runScript" ID="GenericMicroPythonDevice.runScript"></a>
+<h4>GenericMicroPythonDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="GenericMicroPythonDevice.setButtons" ID="GenericMicroPythonDevice.setButtons"></a>
+<h4>GenericMicroPythonDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<a NAME="GenericMicroPythonDevice.supportsLocalFileAccess" ID="GenericMicroPythonDevice.supportsLocalFileAccess"></a>
+<h4>GenericMicroPythonDevice.supportsLocalFileAccess</h4>
+<b>supportsLocalFileAccess</b>(<i></i>)
+
+<p>
+        Public method to indicate file access via a local directory.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating file access via local directory
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+GenericMicroPythonDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,607 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.MicrobitDevices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.MicrobitDevices</h1>
+
+<p>
+Module implementing the device interface class for BBC micro:bit and
+Calliope mini boards.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#MicrobitDevice">MicrobitDevice</a></td>
+<td>Class implementing the device for BBC micro:bit and Calliope mini boards.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="MicrobitDevice" ID="MicrobitDevice"></a>
+<h2>MicrobitDevice</h2>
+
+<p>
+    Class implementing the device for BBC micro:bit and Calliope mini boards.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#MicrobitDevice.__init__">MicrobitDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__createMicrobitMenu">__createMicrobitMenu</a></td>
+<td>Private method to create the microbit submenu.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
+<td>Private method handling the response of the latest version request.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__flashMicroPython">__flashMicroPython</a></td>
+<td>Private slot to flash MicroPython or the DAPLink firmware to the device.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__isCalliope">__isCalliope</a></td>
+<td>Private method to check, if the device is a Calliope mini.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__isMicroBitV1">__isMicroBitV1</a></td>
+<td>Private method to check, if the device is a BBC micro:bit v1.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__isMicroBitV2">__isMicroBitV2</a></td>
+<td>Private method to check, if the device is a BBC micro:bit v2.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__resetDevice">__resetDevice</a></td>
+<td>Private slot to reset the connected device.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__saveMain">__saveMain</a></td>
+<td>Private slot to copy the current script as 'main.py' onto the connected device.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__saveScriptToDevice">__saveScriptToDevice</a></td>
+<td>Private method to save the current script onto the connected device.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
+<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
+<td>Public method to retrieve the entries for the downloads menu.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
+<td>Public method to check, if the device has its own flash menu entry.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.hasTimeCommands">hasTimeCommands</a></td>
+<td>Public method to check, if the device supports time commands.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#MicrobitDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="MicrobitDevice.__init__" ID="MicrobitDevice.__init__"></a>
+<h4>MicrobitDevice (Constructor)</h4>
+<b>MicrobitDevice</b>(<i>microPythonWidget, deviceType, serialNumber, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+type of the device
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__createMicrobitMenu" ID="MicrobitDevice.__createMicrobitMenu"></a>
+<h4>MicrobitDevice.__createMicrobitMenu</h4>
+<b>__createMicrobitMenu</b>(<i></i>)
+
+<p>
+        Private method to create the microbit submenu.
+</p>
+<a NAME="MicrobitDevice.__firmwareVersionResponse" ID="MicrobitDevice.__firmwareVersionResponse"></a>
+<h4>MicrobitDevice.__firmwareVersionResponse</h4>
+<b>__firmwareVersionResponse</b>(<i>reply</i>)
+
+<p>
+        Private method handling the response of the latest version request.
+</p>
+<dl>
+
+<dt><i>reply</i> (QNetworkReply)</dt>
+<dd>
+reference to the reply object
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__flashMicroPython" ID="MicrobitDevice.__flashMicroPython"></a>
+<h4>MicrobitDevice.__flashMicroPython</h4>
+<b>__flashMicroPython</b>(<i>firmware=False</i>)
+
+<p>
+        Private slot to flash MicroPython or the DAPLink firmware to the
+        device.
+</p>
+<dl>
+
+<dt><i>firmware</i> (bool)</dt>
+<dd>
+flag indicating to flash the DAPLink firmware
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__isCalliope" ID="MicrobitDevice.__isCalliope"></a>
+<h4>MicrobitDevice.__isCalliope</h4>
+<b>__isCalliope</b>(<i></i>)
+
+<p>
+        Private method to check, if the device is a Calliope mini.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a Calliope mini
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__isMicroBitV1" ID="MicrobitDevice.__isMicroBitV1"></a>
+<h4>MicrobitDevice.__isMicroBitV1</h4>
+<b>__isMicroBitV1</b>(<i></i>)
+
+<p>
+        Private method to check, if the device is a BBC micro:bit v1.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+falg indicating a BBC micro:bit v1
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__isMicroBitV2" ID="MicrobitDevice.__isMicroBitV2"></a>
+<h4>MicrobitDevice.__isMicroBitV2</h4>
+<b>__isMicroBitV2</b>(<i></i>)
+
+<p>
+        Private method to check, if the device is a BBC micro:bit v2.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+falg indicating a BBC micro:bit v2
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__resetDevice" ID="MicrobitDevice.__resetDevice"></a>
+<h4>MicrobitDevice.__resetDevice</h4>
+<b>__resetDevice</b>(<i></i>)
+
+<p>
+        Private slot to reset the connected device.
+</p>
+<a NAME="MicrobitDevice.__saveMain" ID="MicrobitDevice.__saveMain"></a>
+<h4>MicrobitDevice.__saveMain</h4>
+<b>__saveMain</b>(<i></i>)
+
+<p>
+        Private slot to copy the current script as 'main.py' onto the
+        connected device.
+</p>
+<a NAME="MicrobitDevice.__saveScriptToDevice" ID="MicrobitDevice.__saveScriptToDevice"></a>
+<h4>MicrobitDevice.__saveScriptToDevice</h4>
+<b>__saveScriptToDevice</b>(<i>scriptName=""</i>)
+
+<p>
+        Private method to save the current script onto the connected
+        device.
+</p>
+<dl>
+
+<dt><i>scriptName</i> (str)</dt>
+<dd>
+name of the file on the device
+</dd>
+</dl>
+<a NAME="MicrobitDevice.__showFirmwareVersions" ID="MicrobitDevice.__showFirmwareVersions"></a>
+<h4>MicrobitDevice.__showFirmwareVersions</h4>
+<b>__showFirmwareVersions</b>(<i></i>)
+
+<p>
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+</p>
+<a NAME="MicrobitDevice.addDeviceMenuEntries" ID="MicrobitDevice.addDeviceMenuEntries"></a>
+<h4>MicrobitDevice.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="MicrobitDevice.canRunScript" ID="MicrobitDevice.canRunScript"></a>
+<h4>MicrobitDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="MicrobitDevice.canStartFileManager" ID="MicrobitDevice.canStartFileManager"></a>
+<h4>MicrobitDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="MicrobitDevice.canStartPlotter" ID="MicrobitDevice.canStartPlotter"></a>
+<h4>MicrobitDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="MicrobitDevice.canStartRepl" ID="MicrobitDevice.canStartRepl"></a>
+<h4>MicrobitDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="MicrobitDevice.deviceName" ID="MicrobitDevice.deviceName"></a>
+<h4>MicrobitDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="MicrobitDevice.forceInterrupt" ID="MicrobitDevice.forceInterrupt"></a>
+<h4>MicrobitDevice.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MicrobitDevice.getDocumentationUrl" ID="MicrobitDevice.getDocumentationUrl"></a>
+<h4>MicrobitDevice.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="MicrobitDevice.getDownloadMenuEntries" ID="MicrobitDevice.getDownloadMenuEntries"></a>
+<h4>MicrobitDevice.getDownloadMenuEntries</h4>
+<b>getDownloadMenuEntries</b>(<i></i>)
+
+<p>
+        Public method to retrieve the entries for the downloads menu.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of tuples with menu text and URL to be opened for each
+            entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of tuple of (str, str)
+</dd>
+</dl>
+<a NAME="MicrobitDevice.hasFlashMenuEntry" ID="MicrobitDevice.hasFlashMenuEntry"></a>
+<h4>MicrobitDevice.hasFlashMenuEntry</h4>
+<b>hasFlashMenuEntry</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has its own flash menu entry.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a specific flash menu entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MicrobitDevice.hasTimeCommands" ID="MicrobitDevice.hasTimeCommands"></a>
+<h4>MicrobitDevice.hasTimeCommands</h4>
+<b>hasTimeCommands</b>(<i></i>)
+
+<p>
+        Public method to check, if the device supports time commands.
+</p>
+<p>
+        The default returns True.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating support for time commands
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="MicrobitDevice.runScript" ID="MicrobitDevice.runScript"></a>
+<h4>MicrobitDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="MicrobitDevice.setButtons" ID="MicrobitDevice.setButtons"></a>
+<h4>MicrobitDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+MicrobitDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.PyBoardDevices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,660 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.PyBoardDevices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.PyBoardDevices</h1>
+
+<p>
+Module implementing the device interface class for PyBoard boards.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#PyBoardDevice">PyBoardDevice</a></td>
+<td>Class implementing the device for PyBoard boards.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="PyBoardDevice" ID="PyBoardDevice"></a>
+<h2>PyBoardDevice</h2>
+
+<p>
+    Class implementing the device for PyBoard boards.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>DeviceVolumeName</td></tr><tr><td>FlashInstructionsURL</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#PyBoardDevice.__init__">PyBoardDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__activateBootloader">__activateBootloader</a></td>
+<td>Private slot to activate the bootloader and disconnect.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__createPyboardMenu">__createPyboardMenu</a></td>
+<td>Private method to create the pyboard submenu.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td>
+<td>Private method to check, if the device volume is mounted.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__dfuUtilAvailable">__dfuUtilAvailable</a></td>
+<td>Private method to check the availability of dfu-util.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__findWorkspace">__findWorkspace</a></td>
+<td>Private method to find the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
+<td>Private method handling the response of the latest version request.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__flashMicroPython">__flashMicroPython</a></td>
+<td>Private slot to flash a MicroPython firmware.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__listDfuCapableDevices">__listDfuCapableDevices</a></td>
+<td>Private slot to list all DFU-capable devices.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__showDfuDisableInstructions">__showDfuDisableInstructions</a></td>
+<td>Private method to show some instructions to disable the DFU mode.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__showDfuEnableInstructions">__showDfuEnableInstructions</a></td>
+<td>Private method to show some instructions to enable the DFU mode.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
+<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.__showFlashInstructions">__showFlashInstructions</a></td>
+<td>Private slot to open the URL containing instructions for installing MicroPython on the pyboard.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.getFirmwareUrl">getFirmwareUrl</a></td>
+<td>Public method to get the device firmware download URL.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.getWorkspace">getWorkspace</a></td>
+<td>Public method to get the workspace directory.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
+<td>Public method to check, if the device has its own flash menu entry.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+<tr>
+<td><a href="#PyBoardDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
+<td>Public method to indicate file access via a local directory.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="PyBoardDevice.__init__" ID="PyBoardDevice.__init__"></a>
+<h4>PyBoardDevice (Constructor)</h4>
+<b>PyBoardDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="PyBoardDevice.__activateBootloader" ID="PyBoardDevice.__activateBootloader"></a>
+<h4>PyBoardDevice.__activateBootloader</h4>
+<b>__activateBootloader</b>(<i></i>)
+
+<p>
+        Private slot to activate the bootloader and disconnect.
+</p>
+<a NAME="PyBoardDevice.__createPyboardMenu" ID="PyBoardDevice.__createPyboardMenu"></a>
+<h4>PyBoardDevice.__createPyboardMenu</h4>
+<b>__createPyboardMenu</b>(<i></i>)
+
+<p>
+        Private method to create the pyboard submenu.
+</p>
+<a NAME="PyBoardDevice.__deviceVolumeMounted" ID="PyBoardDevice.__deviceVolumeMounted"></a>
+<h4>PyBoardDevice.__deviceVolumeMounted</h4>
+<b>__deviceVolumeMounted</b>(<i></i>)
+
+<p>
+        Private method to check, if the device volume is mounted.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicated a mounted device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="PyBoardDevice.__dfuUtilAvailable" ID="PyBoardDevice.__dfuUtilAvailable"></a>
+<h4>PyBoardDevice.__dfuUtilAvailable</h4>
+<b>__dfuUtilAvailable</b>(<i></i>)
+
+<p>
+        Private method to check the availability of dfu-util.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating the availability of dfu-util
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="PyBoardDevice.__findWorkspace" ID="PyBoardDevice.__findWorkspace"></a>
+<h4>PyBoardDevice.__findWorkspace</h4>
+<b>__findWorkspace</b>(<i>silent=False</i>)
+
+<p>
+        Private method to find the workspace directory.
+</p>
+<dl>
+
+<dt><i>silent</i> (bool)</dt>
+<dd>
+flag indicating silent operations
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="PyBoardDevice.__firmwareVersionResponse" ID="PyBoardDevice.__firmwareVersionResponse"></a>
+<h4>PyBoardDevice.__firmwareVersionResponse</h4>
+<b>__firmwareVersionResponse</b>(<i>reply</i>)
+
+<p>
+        Private method handling the response of the latest version request.
+</p>
+<dl>
+
+<dt><i>reply</i> (QNetworkReply)</dt>
+<dd>
+reference to the reply object
+</dd>
+</dl>
+<a NAME="PyBoardDevice.__flashMicroPython" ID="PyBoardDevice.__flashMicroPython"></a>
+<h4>PyBoardDevice.__flashMicroPython</h4>
+<b>__flashMicroPython</b>(<i></i>)
+
+<p>
+        Private slot to flash a MicroPython firmware.
+</p>
+<a NAME="PyBoardDevice.__listDfuCapableDevices" ID="PyBoardDevice.__listDfuCapableDevices"></a>
+<h4>PyBoardDevice.__listDfuCapableDevices</h4>
+<b>__listDfuCapableDevices</b>(<i></i>)
+
+<p>
+        Private slot to list all DFU-capable devices.
+</p>
+<a NAME="PyBoardDevice.__showDfuDisableInstructions" ID="PyBoardDevice.__showDfuDisableInstructions"></a>
+<h4>PyBoardDevice.__showDfuDisableInstructions</h4>
+<b>__showDfuDisableInstructions</b>(<i></i>)
+
+<p>
+        Private method to show some instructions to disable the DFU mode.
+</p>
+<a NAME="PyBoardDevice.__showDfuEnableInstructions" ID="PyBoardDevice.__showDfuEnableInstructions"></a>
+<h4>PyBoardDevice.__showDfuEnableInstructions</h4>
+<b>__showDfuEnableInstructions</b>(<i>flash=True</i>)
+
+<p>
+        Private method to show some instructions to enable the DFU mode.
+</p>
+<dl>
+
+<dt><i>flash</i> (bool)</dt>
+<dd>
+flag indicating to show a warning message for flashing
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating OK to continue or abort
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="PyBoardDevice.__showFirmwareVersions" ID="PyBoardDevice.__showFirmwareVersions"></a>
+<h4>PyBoardDevice.__showFirmwareVersions</h4>
+<b>__showFirmwareVersions</b>(<i></i>)
+
+<p>
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+</p>
+<a NAME="PyBoardDevice.__showFlashInstructions" ID="PyBoardDevice.__showFlashInstructions"></a>
+<h4>PyBoardDevice.__showFlashInstructions</h4>
+<b>__showFlashInstructions</b>(<i></i>)
+
+<p>
+        Private slot to open the URL containing instructions for installing
+        MicroPython on the pyboard.
+</p>
+<a NAME="PyBoardDevice.addDeviceMenuEntries" ID="PyBoardDevice.addDeviceMenuEntries"></a>
+<h4>PyBoardDevice.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="PyBoardDevice.canRunScript" ID="PyBoardDevice.canRunScript"></a>
+<h4>PyBoardDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="PyBoardDevice.canStartFileManager" ID="PyBoardDevice.canStartFileManager"></a>
+<h4>PyBoardDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="PyBoardDevice.canStartPlotter" ID="PyBoardDevice.canStartPlotter"></a>
+<h4>PyBoardDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="PyBoardDevice.canStartRepl" ID="PyBoardDevice.canStartRepl"></a>
+<h4>PyBoardDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="PyBoardDevice.deviceName" ID="PyBoardDevice.deviceName"></a>
+<h4>PyBoardDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="PyBoardDevice.forceInterrupt" ID="PyBoardDevice.forceInterrupt"></a>
+<h4>PyBoardDevice.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="PyBoardDevice.getDocumentationUrl" ID="PyBoardDevice.getDocumentationUrl"></a>
+<h4>PyBoardDevice.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="PyBoardDevice.getFirmwareUrl" ID="PyBoardDevice.getFirmwareUrl"></a>
+<h4>PyBoardDevice.getFirmwareUrl</h4>
+<b>getFirmwareUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device firmware download URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+firmware download URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="PyBoardDevice.getWorkspace" ID="PyBoardDevice.getWorkspace"></a>
+<h4>PyBoardDevice.getWorkspace</h4>
+<b>getWorkspace</b>(<i>silent=False</i>)
+
+<p>
+        Public method to get the workspace directory.
+</p>
+<dl>
+
+<dt><i>silent</i> (bool)</dt>
+<dd>
+flag indicating silent operations
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+workspace directory used for saving files
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="PyBoardDevice.hasFlashMenuEntry" ID="PyBoardDevice.hasFlashMenuEntry"></a>
+<h4>PyBoardDevice.hasFlashMenuEntry</h4>
+<b>hasFlashMenuEntry</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has its own flash menu entry.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a specific flash menu entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="PyBoardDevice.runScript" ID="PyBoardDevice.runScript"></a>
+<h4>PyBoardDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="PyBoardDevice.setButtons" ID="PyBoardDevice.setButtons"></a>
+<h4>PyBoardDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<a NAME="PyBoardDevice.supportsLocalFileAccess" ID="PyBoardDevice.supportsLocalFileAccess"></a>
+<h4>PyBoardDevice.supportsLocalFileAccess</h4>
+<b>supportsLocalFileAccess</b>(<i></i>)
+
+<p>
+        Public method to indicate file access via a local directory.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating file access via local directory
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+PyBoardDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.RP2040Devices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,469 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.RP2040Devices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.RP2040Devices</h1>
+
+<p>
+Module implementing the device interface class for RP2040 based boards
+(e.g. Raspberry Pi Pico).
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#RP2040Device">RP2040Device</a></td>
+<td>Class implementing the device for RP2040 based boards.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="RP2040Device" ID="RP2040Device"></a>
+<h2>RP2040Device</h2>
+
+<p>
+    Class implementing the device for RP2040 based boards.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#RP2040Device.__init__">RP2040Device</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.__activateBootloader">__activateBootloader</a></td>
+<td>Private method to switch the board into 'bootloader' mode.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.__createRP2040Menu">__createRP2040Menu</a></td>
+<td>Private method to create the RO2040 submenu.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
+<td>Private method handling the response of the latest version request.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.__flashPython">__flashPython</a></td>
+<td>Private slot to flash a MicroPython firmware to the device.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.__showFirmwareVersions">__showFirmwareVersions</a></td>
+<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
+<td>Public method to retrieve the entries for the downloads menu.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
+<td>Public method to check, if the device has its own flash menu entry.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#RP2040Device.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="RP2040Device.__init__" ID="RP2040Device.__init__"></a>
+<h4>RP2040Device (Constructor)</h4>
+<b>RP2040Device</b>(<i>microPythonWidget, deviceType, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="RP2040Device.__activateBootloader" ID="RP2040Device.__activateBootloader"></a>
+<h4>RP2040Device.__activateBootloader</h4>
+<b>__activateBootloader</b>(<i></i>)
+
+<p>
+        Private method to switch the board into 'bootloader' mode.
+</p>
+<a NAME="RP2040Device.__createRP2040Menu" ID="RP2040Device.__createRP2040Menu"></a>
+<h4>RP2040Device.__createRP2040Menu</h4>
+<b>__createRP2040Menu</b>(<i></i>)
+
+<p>
+        Private method to create the RO2040 submenu.
+</p>
+<a NAME="RP2040Device.__firmwareVersionResponse" ID="RP2040Device.__firmwareVersionResponse"></a>
+<h4>RP2040Device.__firmwareVersionResponse</h4>
+<b>__firmwareVersionResponse</b>(<i>reply</i>)
+
+<p>
+        Private method handling the response of the latest version request.
+</p>
+<dl>
+
+<dt><i>reply</i> (QNetworkReply)</dt>
+<dd>
+reference to the reply object
+</dd>
+</dl>
+<a NAME="RP2040Device.__flashPython" ID="RP2040Device.__flashPython"></a>
+<h4>RP2040Device.__flashPython</h4>
+<b>__flashPython</b>(<i></i>)
+
+<p>
+        Private slot to flash a MicroPython firmware to the device.
+</p>
+<a NAME="RP2040Device.__showFirmwareVersions" ID="RP2040Device.__showFirmwareVersions"></a>
+<h4>RP2040Device.__showFirmwareVersions</h4>
+<b>__showFirmwareVersions</b>(<i></i>)
+
+<p>
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+</p>
+<a NAME="RP2040Device.addDeviceMenuEntries" ID="RP2040Device.addDeviceMenuEntries"></a>
+<h4>RP2040Device.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="RP2040Device.canRunScript" ID="RP2040Device.canRunScript"></a>
+<h4>RP2040Device.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="RP2040Device.canStartFileManager" ID="RP2040Device.canStartFileManager"></a>
+<h4>RP2040Device.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="RP2040Device.canStartPlotter" ID="RP2040Device.canStartPlotter"></a>
+<h4>RP2040Device.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="RP2040Device.canStartRepl" ID="RP2040Device.canStartRepl"></a>
+<h4>RP2040Device.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="RP2040Device.deviceName" ID="RP2040Device.deviceName"></a>
+<h4>RP2040Device.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="RP2040Device.forceInterrupt" ID="RP2040Device.forceInterrupt"></a>
+<h4>RP2040Device.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="RP2040Device.getDocumentationUrl" ID="RP2040Device.getDocumentationUrl"></a>
+<h4>RP2040Device.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="RP2040Device.getDownloadMenuEntries" ID="RP2040Device.getDownloadMenuEntries"></a>
+<h4>RP2040Device.getDownloadMenuEntries</h4>
+<b>getDownloadMenuEntries</b>(<i></i>)
+
+<p>
+        Public method to retrieve the entries for the downloads menu.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+list of tuples with menu text and URL to be opened for each
+            entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+list of tuple of (str, str)
+</dd>
+</dl>
+<a NAME="RP2040Device.hasFlashMenuEntry" ID="RP2040Device.hasFlashMenuEntry"></a>
+<h4>RP2040Device.hasFlashMenuEntry</h4>
+<b>hasFlashMenuEntry</b>(<i></i>)
+
+<p>
+        Public method to check, if the device has its own flash menu entry.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating a specific flash menu entry
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="RP2040Device.runScript" ID="RP2040Device.runScript"></a>
+<h4>RP2040Device.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="RP2040Device.setButtons" ID="RP2040Device.setButtons"></a>
+<h4>RP2040Device.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+RP2040Device
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.TeensyDevices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,447 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.TeensyDevices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.TeensyDevices</h1>
+
+<p>
+Module implementing the device interface class for Teensy boards with MicroPython.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+
+<tr>
+<td><a href="#TeensyDevice">TeensyDevice</a></td>
+<td>Class implementing the device for Teensy boards with MicroPython.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#createDevice">createDevice</a></td>
+<td>Function to instantiate a MicroPython device object.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="TeensyDevice" ID="TeensyDevice"></a>
+<h2>TeensyDevice</h2>
+
+<p>
+    Class implementing the device for Teensy boards with MicroPython.
+</p>
+<h3>Derived from</h3>
+BaseDevice
+<h3>Class Attributes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+
+<table>
+
+<tr>
+<td><a href="#TeensyDevice.__init__">TeensyDevice</a></td>
+<td>Constructor</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.__createTeensyMenu">__createTeensyMenu</a></td>
+<td>Private method to create the microbit submenu.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
+<td>Private method handling the response of the latest version request.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
+<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.__showFlashInstructions">__showFlashInstructions</a></td>
+<td>Private method to show a message box with instruction to flash the Teensy.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.__startTeensyLoader">__startTeensyLoader</a></td>
+<td>Private method to start the 'Teensy Loader' application.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
+<td>Public method to add device specific entries to the given menu.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.canRunScript">canRunScript</a></td>
+<td>Public method to determine, if a script can be executed.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.canStartFileManager">canStartFileManager</a></td>
+<td>Public method to determine, if a File Manager can be started.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.canStartPlotter">canStartPlotter</a></td>
+<td>Public method to determine, if a Plotter can be started.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.canStartRepl">canStartRepl</a></td>
+<td>Public method to determine, if a REPL can be started.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.deviceName">deviceName</a></td>
+<td>Public method to get the name of the device.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.forceInterrupt">forceInterrupt</a></td>
+<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.getDocumentationUrl">getDocumentationUrl</a></td>
+<td>Public method to get the device documentation URL.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.getFirmwareUrl">getFirmwareUrl</a></td>
+<td>Public method to get the device firmware download URL.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.runScript">runScript</a></td>
+<td>Public method to run the given Python script.</td>
+</tr>
+<tr>
+<td><a href="#TeensyDevice.setButtons">setButtons</a></td>
+<td>Public method to enable the supported action buttons.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+
+<a NAME="TeensyDevice.__init__" ID="TeensyDevice.__init__"></a>
+<h4>TeensyDevice (Constructor)</h4>
+<b>TeensyDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
+
+<p>
+        Constructor
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>parent</i> (QObject)</dt>
+<dd>
+reference to the parent object
+</dd>
+</dl>
+<a NAME="TeensyDevice.__createTeensyMenu" ID="TeensyDevice.__createTeensyMenu"></a>
+<h4>TeensyDevice.__createTeensyMenu</h4>
+<b>__createTeensyMenu</b>(<i></i>)
+
+<p>
+        Private method to create the microbit submenu.
+</p>
+<a NAME="TeensyDevice.__firmwareVersionResponse" ID="TeensyDevice.__firmwareVersionResponse"></a>
+<h4>TeensyDevice.__firmwareVersionResponse</h4>
+<b>__firmwareVersionResponse</b>(<i>reply</i>)
+
+<p>
+        Private method handling the response of the latest version request.
+</p>
+<dl>
+
+<dt><i>reply</i> (QNetworkReply)</dt>
+<dd>
+reference to the reply object
+</dd>
+</dl>
+<a NAME="TeensyDevice.__showFirmwareVersions" ID="TeensyDevice.__showFirmwareVersions"></a>
+<h4>TeensyDevice.__showFirmwareVersions</h4>
+<b>__showFirmwareVersions</b>(<i></i>)
+
+<p>
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+</p>
+<a NAME="TeensyDevice.__showFlashInstructions" ID="TeensyDevice.__showFlashInstructions"></a>
+<h4>TeensyDevice.__showFlashInstructions</h4>
+<b>__showFlashInstructions</b>(<i></i>)
+
+<p>
+        Private method to show a message box with instruction to flash the Teensy.
+</p>
+<a NAME="TeensyDevice.__startTeensyLoader" ID="TeensyDevice.__startTeensyLoader"></a>
+<h4>TeensyDevice.__startTeensyLoader</h4>
+<b>__startTeensyLoader</b>(<i></i>)
+
+<p>
+        Private method to start the 'Teensy Loader' application.
+</p>
+<p>
+        Note: The application must be accessible via the application search path.
+</p>
+<a NAME="TeensyDevice.addDeviceMenuEntries" ID="TeensyDevice.addDeviceMenuEntries"></a>
+<h4>TeensyDevice.addDeviceMenuEntries</h4>
+<b>addDeviceMenuEntries</b>(<i>menu</i>)
+
+<p>
+        Public method to add device specific entries to the given menu.
+</p>
+<dl>
+
+<dt><i>menu</i> (QMenu)</dt>
+<dd>
+reference to the context menu
+</dd>
+</dl>
+<a NAME="TeensyDevice.canRunScript" ID="TeensyDevice.canRunScript"></a>
+<h4>TeensyDevice.canRunScript</h4>
+<b>canRunScript</b>(<i></i>)
+
+<p>
+        Public method to determine, if a script can be executed.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="TeensyDevice.canStartFileManager" ID="TeensyDevice.canStartFileManager"></a>
+<h4>TeensyDevice.canStartFileManager</h4>
+<b>canStartFileManager</b>(<i></i>)
+
+<p>
+        Public method to determine, if a File Manager can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="TeensyDevice.canStartPlotter" ID="TeensyDevice.canStartPlotter"></a>
+<h4>TeensyDevice.canStartPlotter</h4>
+<b>canStartPlotter</b>(<i></i>)
+
+<p>
+        Public method to determine, if a Plotter can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="TeensyDevice.canStartRepl" ID="TeensyDevice.canStartRepl"></a>
+<h4>TeensyDevice.canStartRepl</h4>
+<b>canStartRepl</b>(<i></i>)
+
+<p>
+        Public method to determine, if a REPL can be started.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (bool, str)
+</dd>
+</dl>
+<a NAME="TeensyDevice.deviceName" ID="TeensyDevice.deviceName"></a>
+<h4>TeensyDevice.deviceName</h4>
+<b>deviceName</b>(<i></i>)
+
+<p>
+        Public method to get the name of the device.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+name of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="TeensyDevice.forceInterrupt" ID="TeensyDevice.forceInterrupt"></a>
+<h4>TeensyDevice.forceInterrupt</h4>
+<b>forceInterrupt</b>(<i></i>)
+
+<p>
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+flag indicating an interrupt is needed
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+bool
+</dd>
+</dl>
+<a NAME="TeensyDevice.getDocumentationUrl" ID="TeensyDevice.getDocumentationUrl"></a>
+<h4>TeensyDevice.getDocumentationUrl</h4>
+<b>getDocumentationUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device documentation URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+documentation URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="TeensyDevice.getFirmwareUrl" ID="TeensyDevice.getFirmwareUrl"></a>
+<h4>TeensyDevice.getFirmwareUrl</h4>
+<b>getFirmwareUrl</b>(<i></i>)
+
+<p>
+        Public method to get the device firmware download URL.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+firmware download URL of the device
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+str
+</dd>
+</dl>
+<a NAME="TeensyDevice.runScript" ID="TeensyDevice.runScript"></a>
+<h4>TeensyDevice.runScript</h4>
+<b>runScript</b>(<i>script</i>)
+
+<p>
+        Public method to run the given Python script.
+</p>
+<dl>
+
+<dt><i>script</i> (str)</dt>
+<dd>
+script to be executed
+</dd>
+</dl>
+<a NAME="TeensyDevice.setButtons" ID="TeensyDevice.setButtons"></a>
+<h4>TeensyDevice.setButtons</h4>
+<b>setButtons</b>(<i></i>)
+
+<p>
+        Public method to enable the supported action buttons.
+</p>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="createDevice" ID="createDevice"></a>
+<h2>createDevice</h2>
+<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
+
+<p>
+    Function to instantiate a MicroPython device object.
+</p>
+<dl>
+
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+device type assigned to this device interface
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID
+</dd>
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>serialNumber</i> (str)</dt>
+<dd>
+serial number of the board
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+reference to the instantiated device object
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+PyBoardDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.__init__.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.__init__</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<a NAME="top" ID="top"></a>
+<h1>eric7.MicroPython.Devices.__init__</h1>
+
+<p>
+Package containing the device interface modules and device specific dialogs.
+</p>
+<h3>Global Attributes</h3>
+
+<table>
+<tr><td>FirmwareGithubUrls</td></tr><tr><td>IgnoredBoards</td></tr><tr><td>SupportedBoards</td></tr>
+</table>
+<h3>Classes</h3>
+
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Functions</h3>
+
+<table>
+
+<tr>
+<td><a href="#getDevice">getDevice</a></td>
+<td>Public method to instantiate a specific MicroPython device interface.</td>
+</tr>
+<tr>
+<td><a href="#getDeviceIcon">getDeviceIcon</a></td>
+<td>Function to get the icon for the given board.</td>
+</tr>
+<tr>
+<td><a href="#getFoundDevices">getFoundDevices</a></td>
+<td>Function to check the serial ports for supported MicroPython devices.</td>
+</tr>
+<tr>
+<td><a href="#getSupportedDevices">getSupportedDevices</a></td>
+<td>Function to get a list of supported MicroPython devices.</td>
+</tr>
+</table>
+<hr />
+<hr />
+<a NAME="getDevice" ID="getDevice"></a>
+<h2>getDevice</h2>
+<b>getDevice</b>(<i>deviceType, microPythonWidget, vid, pid, boardName="", serialNumber=""</i>)
+
+<p>
+    Public method to instantiate a specific MicroPython device interface.
+</p>
+<dl>
+
+<dt><i>deviceType</i> (str)</dt>
+<dd>
+type of the device interface
+</dd>
+<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
+<dd>
+reference to the main MicroPython widget
+</dd>
+<dt><i>vid</i> (int)</dt>
+<dd>
+vendor ID (only used for deviceType 'generic')
+</dd>
+<dt><i>pid</i> (int)</dt>
+<dd>
+product ID (only used for deviceType 'generic')
+</dd>
+<dt><i>boardName</i> (str (optional))</dt>
+<dd>
+name of the board (defaults to "")
+</dd>
+<dt><i>serialNumber</i> (str (optional))</dt>
+<dd>
+serial number of the board (defaults to "")
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+instantiated device interface
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+BaseDevice
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="getDeviceIcon" ID="getDeviceIcon"></a>
+<h2>getDeviceIcon</h2>
+<b>getDeviceIcon</b>(<i>boardName, iconFormat=True</i>)
+
+<p>
+    Function to get the icon for the given board.
+</p>
+<dl>
+
+<dt><i>boardName</i> (str)</dt>
+<dd>
+name of the board
+</dd>
+<dt><i>iconFormat</i> (bool)</dt>
+<dd>
+flag indicating to get an icon or a pixmap
+</dd>
+</dl>
+<dl>
+<dt>Return:</dt>
+<dd>
+icon for the board (iconFormat == True) or
+        a pixmap (iconFormat == False)
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+QIcon or QPixmap
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="getFoundDevices" ID="getFoundDevices"></a>
+<h2>getFoundDevices</h2>
+<b>getFoundDevices</b>(<i></i>)
+
+<p>
+    Function to check the serial ports for supported MicroPython devices.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+tuple containing a list of tuples with the board type, the port
+        description, a description, the serial port it is connected at, the
+        VID and PID for known device types, a list of tuples with VID, PID
+        and description for unknown devices and a list of tuples with VID,
+        PID, description and port name for ports with missing VID or PID
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+tuple of (list of tuples of (str, str, str, str, int, int),
+        list of tuples of (int, int, str),
+        list of tuples of (int, int, str, str)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+<hr />
+<a NAME="getSupportedDevices" ID="getSupportedDevices"></a>
+<h2>getSupportedDevices</h2>
+<b>getSupportedDevices</b>(<i></i>)
+
+<p>
+    Function to get a list of supported MicroPython devices.
+</p>
+<dl>
+<dt>Return:</dt>
+<dd>
+set of tuples with the board type and description
+</dd>
+</dl>
+<dl>
+<dt>Return Type:</dt>
+<dd>
+set of tuples of (str, str)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.EspBackupRestoreFirmwareDialog.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.EspBackupRestoreFirmwareDialog</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.EspBackupRestoreFirmwareDialog</h1>
-
-<p>
-Module implementing a dialog to select the ESP chip type and the backup and
-restore parameters.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog">EspBackupRestoreFirmwareDialog</a></td>
-<td>Class implementing a dialog to select the ESP chip type and the backup and restore parameters.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr />
-<hr />
-<a NAME="EspBackupRestoreFirmwareDialog" ID="EspBackupRestoreFirmwareDialog"></a>
-<h2>EspBackupRestoreFirmwareDialog</h2>
-
-<p>
-    Class implementing a dialog to select the ESP chip type and the backup and
-    restore parameters.
-</p>
-<h3>Derived from</h3>
-QDialog, Ui_EspBackupRestoreFirmwareDialog
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>Chips</td></tr><tr><td>FlashModes</td></tr><tr><td>FlashSizes</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog.__init__">EspBackupRestoreFirmwareDialog</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog.__updateOkButton">__updateOkButton</a></td>
-<td>Private method to update the state of the OK button.</td>
-</tr>
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog.getData">getData</a></td>
-<td>Public method to get the entered data.</td>
-</tr>
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged">on_espComboBox_currentTextChanged</a></td>
-<td>Private slot to handle the selection of a chip type.</td>
-</tr>
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged">on_firmwarePicker_textChanged</a></td>
-<td>Private slot handling a change of the firmware path.</td>
-</tr>
-<tr>
-<td><a href="#EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged">on_sizeComboBox_currentTextChanged</a></td>
-<td>Private slot handling a change of the selected firmware size.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="EspBackupRestoreFirmwareDialog.__init__" ID="EspBackupRestoreFirmwareDialog.__init__"></a>
-<h4>EspBackupRestoreFirmwareDialog (Constructor)</h4>
-<b>EspBackupRestoreFirmwareDialog</b>(<i>backupMode=True, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>backupMode</i> (bool)</dt>
-<dd>
-flag indicating parameters for a firmware backup are
-            requested
-</dd>
-<dt><i>parent</i> (QWidget)</dt>
-<dd>
-reference to the parent widget
-</dd>
-</dl>
-<a NAME="EspBackupRestoreFirmwareDialog.__updateOkButton" ID="EspBackupRestoreFirmwareDialog.__updateOkButton"></a>
-<h4>EspBackupRestoreFirmwareDialog.__updateOkButton</h4>
-<b>__updateOkButton</b>(<i></i>)
-
-<p>
-        Private method to update the state of the OK button.
-</p>
-<a NAME="EspBackupRestoreFirmwareDialog.getData" ID="EspBackupRestoreFirmwareDialog.getData"></a>
-<h4>EspBackupRestoreFirmwareDialog.getData</h4>
-<b>getData</b>(<i></i>)
-
-<p>
-        Public method to get the entered data.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing the selected chip type, the firmware size,
-            the baud rate or flashing, the flash mode and the path of the
-            firmware file
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (str, str, str, str, str)
-</dd>
-</dl>
-<a NAME="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged" ID="EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged"></a>
-<h4>EspBackupRestoreFirmwareDialog.on_espComboBox_currentTextChanged</h4>
-<b>on_espComboBox_currentTextChanged</b>(<i>chip</i>)
-
-<p>
-        Private slot to handle the selection of a chip type.
-</p>
-<dl>
-
-<dt><i>chip</i> (str)</dt>
-<dd>
-selected chip type
-</dd>
-</dl>
-<a NAME="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged" ID="EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged"></a>
-<h4>EspBackupRestoreFirmwareDialog.on_firmwarePicker_textChanged</h4>
-<b>on_firmwarePicker_textChanged</b>(<i>firmware</i>)
-
-<p>
-        Private slot handling a change of the firmware path.
-</p>
-<dl>
-
-<dt><i>firmware</i> (str)</dt>
-<dd>
-path to the firmware
-</dd>
-</dl>
-<a NAME="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged" ID="EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged"></a>
-<h4>EspBackupRestoreFirmwareDialog.on_sizeComboBox_currentTextChanged</h4>
-<b>on_sizeComboBox_currentTextChanged</b>(<i>size</i>)
-
-<p>
-        Private slot handling a change of the selected firmware size.
-</p>
-<dl>
-
-<dt><i>size</i> (str)</dt>
-<dd>
-selected size text
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.EspDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,556 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.EspDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.EspDevices</h1>
-
-<p>
-Module implementing the device interface class for ESP32 and ESP8266 based
-boards.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#EspDevice">EspDevice</a></td>
-<td>Class implementing the device for ESP32 and ESP8266 based boards.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="EspDevice" ID="EspDevice"></a>
-<h2>EspDevice</h2>
-
-<p>
-    Class implementing the device for ESP32 and ESP8266 based boards.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#EspDevice.__init__">EspDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__backupFlash">__backupFlash</a></td>
-<td>Private slot to backup the currently flashed firmware.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__createEsp32Submenu">__createEsp32Submenu</a></td>
-<td>Private method to create the ESP32 submenu.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__eraseFlash">__eraseFlash</a></td>
-<td>Private slot to erase the device flash memory.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
-<td>Private method handling the response of the latest version request.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__flashAddons">__flashAddons</a></td>
-<td>Private slot to flash some additional firmware images.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__flashMicroPython">__flashMicroPython</a></td>
-<td>Private slot to flash a MicroPython firmware to the device.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__installEspTool">__installEspTool</a></td>
-<td>Private slot to install the esptool package via pip.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__resetDevice">__resetDevice</a></td>
-<td>Private slot to reset the connected device.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__restoreFlash">__restoreFlash</a></td>
-<td>Private slot to restore a previously saved firmware.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__showChipID">__showChipID</a></td>
-<td>Private slot to show the ID of the ESP chip.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
-<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__showFlashID">__showFlashID</a></td>
-<td>Private slot to show the ID of the ESP flash chip.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.__showMACAddress">__showMACAddress</a></td>
-<td>Private slot to show the MAC address of the ESP chip.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.getFirmwareUrl">getFirmwareUrl</a></td>
-<td>Public method to get the device firmware download URL.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
-<td>Public method to check, if the device has its own flash menu entry.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#EspDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="EspDevice.__init__" ID="EspDevice.__init__"></a>
-<h4>EspDevice (Constructor)</h4>
-<b>EspDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="EspDevice.__backupFlash" ID="EspDevice.__backupFlash"></a>
-<h4>EspDevice.__backupFlash</h4>
-<b>__backupFlash</b>(<i></i>)
-
-<p>
-        Private slot to backup the currently flashed firmware.
-</p>
-<a NAME="EspDevice.__createEsp32Submenu" ID="EspDevice.__createEsp32Submenu"></a>
-<h4>EspDevice.__createEsp32Submenu</h4>
-<b>__createEsp32Submenu</b>(<i></i>)
-
-<p>
-        Private method to create the ESP32 submenu.
-</p>
-<a NAME="EspDevice.__eraseFlash" ID="EspDevice.__eraseFlash"></a>
-<h4>EspDevice.__eraseFlash</h4>
-<b>__eraseFlash</b>(<i></i>)
-
-<p>
-        Private slot to erase the device flash memory.
-</p>
-<a NAME="EspDevice.__firmwareVersionResponse" ID="EspDevice.__firmwareVersionResponse"></a>
-<h4>EspDevice.__firmwareVersionResponse</h4>
-<b>__firmwareVersionResponse</b>(<i>reply</i>)
-
-<p>
-        Private method handling the response of the latest version request.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the reply object
-</dd>
-</dl>
-<a NAME="EspDevice.__flashAddons" ID="EspDevice.__flashAddons"></a>
-<h4>EspDevice.__flashAddons</h4>
-<b>__flashAddons</b>(<i></i>)
-
-<p>
-        Private slot to flash some additional firmware images.
-</p>
-<a NAME="EspDevice.__flashMicroPython" ID="EspDevice.__flashMicroPython"></a>
-<h4>EspDevice.__flashMicroPython</h4>
-<b>__flashMicroPython</b>(<i></i>)
-
-<p>
-        Private slot to flash a MicroPython firmware to the device.
-</p>
-<a NAME="EspDevice.__installEspTool" ID="EspDevice.__installEspTool"></a>
-<h4>EspDevice.__installEspTool</h4>
-<b>__installEspTool</b>(<i></i>)
-
-<p>
-        Private slot to install the esptool package via pip.
-</p>
-<a NAME="EspDevice.__resetDevice" ID="EspDevice.__resetDevice"></a>
-<h4>EspDevice.__resetDevice</h4>
-<b>__resetDevice</b>(<i></i>)
-
-<p>
-        Private slot to reset the connected device.
-</p>
-<a NAME="EspDevice.__restoreFlash" ID="EspDevice.__restoreFlash"></a>
-<h4>EspDevice.__restoreFlash</h4>
-<b>__restoreFlash</b>(<i></i>)
-
-<p>
-        Private slot to restore a previously saved firmware.
-</p>
-<a NAME="EspDevice.__showChipID" ID="EspDevice.__showChipID"></a>
-<h4>EspDevice.__showChipID</h4>
-<b>__showChipID</b>(<i></i>)
-
-<p>
-        Private slot to show the ID of the ESP chip.
-</p>
-<a NAME="EspDevice.__showFirmwareVersions" ID="EspDevice.__showFirmwareVersions"></a>
-<h4>EspDevice.__showFirmwareVersions</h4>
-<b>__showFirmwareVersions</b>(<i></i>)
-
-<p>
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-</p>
-<a NAME="EspDevice.__showFlashID" ID="EspDevice.__showFlashID"></a>
-<h4>EspDevice.__showFlashID</h4>
-<b>__showFlashID</b>(<i></i>)
-
-<p>
-        Private slot to show the ID of the ESP flash chip.
-</p>
-<a NAME="EspDevice.__showMACAddress" ID="EspDevice.__showMACAddress"></a>
-<h4>EspDevice.__showMACAddress</h4>
-<b>__showMACAddress</b>(<i></i>)
-
-<p>
-        Private slot to show the MAC address of the ESP chip.
-</p>
-<a NAME="EspDevice.addDeviceMenuEntries" ID="EspDevice.addDeviceMenuEntries"></a>
-<h4>EspDevice.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="EspDevice.canRunScript" ID="EspDevice.canRunScript"></a>
-<h4>EspDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="EspDevice.canStartFileManager" ID="EspDevice.canStartFileManager"></a>
-<h4>EspDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="EspDevice.canStartPlotter" ID="EspDevice.canStartPlotter"></a>
-<h4>EspDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="EspDevice.canStartRepl" ID="EspDevice.canStartRepl"></a>
-<h4>EspDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="EspDevice.deviceName" ID="EspDevice.deviceName"></a>
-<h4>EspDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="EspDevice.forceInterrupt" ID="EspDevice.forceInterrupt"></a>
-<h4>EspDevice.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="EspDevice.getDocumentationUrl" ID="EspDevice.getDocumentationUrl"></a>
-<h4>EspDevice.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="EspDevice.getFirmwareUrl" ID="EspDevice.getFirmwareUrl"></a>
-<h4>EspDevice.getFirmwareUrl</h4>
-<b>getFirmwareUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device firmware download URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-firmware download URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="EspDevice.hasFlashMenuEntry" ID="EspDevice.hasFlashMenuEntry"></a>
-<h4>EspDevice.hasFlashMenuEntry</h4>
-<b>hasFlashMenuEntry</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has its own flash menu entry.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a specific flash menu entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="EspDevice.runScript" ID="EspDevice.runScript"></a>
-<h4>EspDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="EspDevice.setButtons" ID="EspDevice.setButtons"></a>
-<h4>EspDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-EspDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.EspFirmwareSelectionDialog.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.EspFirmwareSelectionDialog</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.EspFirmwareSelectionDialog</h1>
-
-<p>
-Module implementing a dialog to select the ESP chip type and the firmware to
-be flashed.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#EspFirmwareSelectionDialog">EspFirmwareSelectionDialog</a></td>
-<td>Class implementing a dialog to select the ESP chip type and the firmware to be flashed.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<hr />
-<hr />
-<a NAME="EspFirmwareSelectionDialog" ID="EspFirmwareSelectionDialog"></a>
-<h2>EspFirmwareSelectionDialog</h2>
-
-<p>
-    Class implementing a dialog to select the ESP chip type and the firmware to
-    be flashed.
-</p>
-<h3>Derived from</h3>
-QDialog, Ui_EspFirmwareSelectionDialog
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>Chips</td></tr><tr><td>FlashAddresses</td></tr><tr><td>FlashModes</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#EspFirmwareSelectionDialog.__init__">EspFirmwareSelectionDialog</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#EspFirmwareSelectionDialog.__updateOkButton">__updateOkButton</a></td>
-<td>Private method to update the state of the OK button.</td>
-</tr>
-<tr>
-<td><a href="#EspFirmwareSelectionDialog.getData">getData</a></td>
-<td>Public method to get the entered data.</td>
-</tr>
-<tr>
-<td><a href="#EspFirmwareSelectionDialog.on_addressEdit_textChanged">on_addressEdit_textChanged</a></td>
-<td>Private slot handling a change of the address.</td>
-</tr>
-<tr>
-<td><a href="#EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged">on_espComboBox_currentTextChanged</a></td>
-<td>Private slot to handle the selection of a chip type.</td>
-</tr>
-<tr>
-<td><a href="#EspFirmwareSelectionDialog.on_firmwarePicker_textChanged">on_firmwarePicker_textChanged</a></td>
-<td>Private slot handling a change of the firmware path.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="EspFirmwareSelectionDialog.__init__" ID="EspFirmwareSelectionDialog.__init__"></a>
-<h4>EspFirmwareSelectionDialog (Constructor)</h4>
-<b>EspFirmwareSelectionDialog</b>(<i>addon=False, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>addon</i> (bool)</dt>
-<dd>
-flag indicating an addon firmware
-</dd>
-<dt><i>parent</i> (QWidget)</dt>
-<dd>
-reference to the parent widget
-</dd>
-</dl>
-<a NAME="EspFirmwareSelectionDialog.__updateOkButton" ID="EspFirmwareSelectionDialog.__updateOkButton"></a>
-<h4>EspFirmwareSelectionDialog.__updateOkButton</h4>
-<b>__updateOkButton</b>(<i></i>)
-
-<p>
-        Private method to update the state of the OK button.
-</p>
-<a NAME="EspFirmwareSelectionDialog.getData" ID="EspFirmwareSelectionDialog.getData"></a>
-<h4>EspFirmwareSelectionDialog.getData</h4>
-<b>getData</b>(<i></i>)
-
-<p>
-        Public method to get the entered data.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing the selected chip type, the path of the
-            firmware file, the baud rate, the flash mode and the flash
-            address
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (str, str, str, str, str)
-</dd>
-</dl>
-<a NAME="EspFirmwareSelectionDialog.on_addressEdit_textChanged" ID="EspFirmwareSelectionDialog.on_addressEdit_textChanged"></a>
-<h4>EspFirmwareSelectionDialog.on_addressEdit_textChanged</h4>
-<b>on_addressEdit_textChanged</b>(<i>address</i>)
-
-<p>
-        Private slot handling a change of the address.
-</p>
-<dl>
-
-<dt><i>address</i> (str)</dt>
-<dd>
-entered address
-</dd>
-</dl>
-<a NAME="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged" ID="EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged"></a>
-<h4>EspFirmwareSelectionDialog.on_espComboBox_currentTextChanged</h4>
-<b>on_espComboBox_currentTextChanged</b>(<i>chip</i>)
-
-<p>
-        Private slot to handle the selection of a chip type.
-</p>
-<dl>
-
-<dt><i>chip</i> (str)</dt>
-<dd>
-selected chip type
-</dd>
-</dl>
-<a NAME="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged" ID="EspFirmwareSelectionDialog.on_firmwarePicker_textChanged"></a>
-<h4>EspFirmwareSelectionDialog.on_firmwarePicker_textChanged</h4>
-<b>on_firmwarePicker_textChanged</b>(<i>firmware</i>)
-
-<p>
-        Private slot handling a change of the firmware path.
-</p>
-<dl>
-
-<dt><i>firmware</i> (str)</dt>
-<dd>
-path to the firmware
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.GenericMicroPythonDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.GenericMicroPythonDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.GenericMicroPythonDevices</h1>
-
-<p>
-Module implementing the device interface class for generic MicroPython devices
-(i.e. those devices not specifically supported yet).
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#GenericMicroPythonDevice">GenericMicroPythonDevice</a></td>
-<td>Class implementing the device interface for generic MicroPython boards.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="GenericMicroPythonDevice" ID="GenericMicroPythonDevice"></a>
-<h2>GenericMicroPythonDevice</h2>
-
-<p>
-    Class implementing the device interface for generic MicroPython boards.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#GenericMicroPythonDevice.__init__">GenericMicroPythonDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td>
-<td>Private method to check, if the device volume is mounted.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.__findWorkspace">__findWorkspace</a></td>
-<td>Private method to find the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.getWorkspace">getWorkspace</a></td>
-<td>Public method to get the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-<tr>
-<td><a href="#GenericMicroPythonDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
-<td>Public method to indicate file access via a local directory.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="GenericMicroPythonDevice.__init__" ID="GenericMicroPythonDevice.__init__"></a>
-<h4>GenericMicroPythonDevice (Constructor)</h4>
-<b>GenericMicroPythonDevice</b>(<i>microPythonWidget, deviceType, vid, pid, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.__deviceVolumeMounted" ID="GenericMicroPythonDevice.__deviceVolumeMounted"></a>
-<h4>GenericMicroPythonDevice.__deviceVolumeMounted</h4>
-<b>__deviceVolumeMounted</b>(<i></i>)
-
-<p>
-        Private method to check, if the device volume is mounted.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicated a mounted device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.__findWorkspace" ID="GenericMicroPythonDevice.__findWorkspace"></a>
-<h4>GenericMicroPythonDevice.__findWorkspace</h4>
-<b>__findWorkspace</b>(<i>silent=False</i>)
-
-<p>
-        Private method to find the workspace directory.
-</p>
-<dl>
-
-<dt><i>silent</i> (bool)</dt>
-<dd>
-flag indicating silent operations
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.canRunScript" ID="GenericMicroPythonDevice.canRunScript"></a>
-<h4>GenericMicroPythonDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.canStartFileManager" ID="GenericMicroPythonDevice.canStartFileManager"></a>
-<h4>GenericMicroPythonDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.canStartPlotter" ID="GenericMicroPythonDevice.canStartPlotter"></a>
-<h4>GenericMicroPythonDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.canStartRepl" ID="GenericMicroPythonDevice.canStartRepl"></a>
-<h4>GenericMicroPythonDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.deviceName" ID="GenericMicroPythonDevice.deviceName"></a>
-<h4>GenericMicroPythonDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.getWorkspace" ID="GenericMicroPythonDevice.getWorkspace"></a>
-<h4>GenericMicroPythonDevice.getWorkspace</h4>
-<b>getWorkspace</b>(<i>silent=False</i>)
-
-<p>
-        Public method to get the workspace directory.
-</p>
-<dl>
-
-<dt><i>silent</i> (bool)</dt>
-<dd>
-flag indicating silent operations
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.runScript" ID="GenericMicroPythonDevice.runScript"></a>
-<h4>GenericMicroPythonDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="GenericMicroPythonDevice.setButtons" ID="GenericMicroPythonDevice.setButtons"></a>
-<h4>GenericMicroPythonDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<a NAME="GenericMicroPythonDevice.supportsLocalFileAccess" ID="GenericMicroPythonDevice.supportsLocalFileAccess"></a>
-<h4>GenericMicroPythonDevice.supportsLocalFileAccess</h4>
-<b>supportsLocalFileAccess</b>(<i></i>)
-
-<p>
-        Public method to indicate file access via a local directory.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating file access via local directory
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-GenericMicroPythonDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.MicroPythonDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,862 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.MicroPythonDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.MicroPythonDevices</h1>
-
-<p>
-Module implementing some utility functions and the MicroPythonDevice base
-class.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>FirmwareGithubUrls</td></tr><tr><td>IgnoredBoards</td></tr><tr><td>SupportedBoards</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#MicroPythonDevice">MicroPythonDevice</a></td>
-<td>Base class for the more specific MicroPython devices.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#getDevice">getDevice</a></td>
-<td>Public method to instantiate a specific MicroPython device interface.</td>
-</tr>
-<tr>
-<td><a href="#getDeviceIcon">getDeviceIcon</a></td>
-<td>Function to get the icon for the given board.</td>
-</tr>
-<tr>
-<td><a href="#getFoundDevices">getFoundDevices</a></td>
-<td>Function to check the serial ports for supported MicroPython devices.</td>
-</tr>
-<tr>
-<td><a href="#getSupportedDevices">getSupportedDevices</a></td>
-<td>Function to get a list of supported MicroPython devices.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="MicroPythonDevice" ID="MicroPythonDevice"></a>
-<h2>MicroPythonDevice</h2>
-
-<p>
-    Base class for the more specific MicroPython devices.
-</p>
-<h3>Derived from</h3>
-QObject
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#MicroPythonDevice.__init__">MicroPythonDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.checkDeviceData">checkDeviceData</a></td>
-<td>Public method to check the validity of the device data determined during connecting the device.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.downloadFirmware">downloadFirmware</a></td>
-<td>Public method to download the device firmware.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.getDeviceData">getDeviceData</a></td>
-<td>Public method to get a copy of the determined device data.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.getDeviceType">getDeviceType</a></td>
-<td>Public method to get the device type.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
-<td>Public method to retrieve the entries for the downloads menu.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.getFirmwareUrl">getFirmwareUrl</a></td>
-<td>Public method to get the device firmware download URL.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.getWorkspace">getWorkspace</a></td>
-<td>Public method to get the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.handleDataFlood">handleDataFlood</a></td>
-<td>Public slot handling a data floof from the device.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.hasDocumentationUrl">hasDocumentationUrl</a></td>
-<td>Public method to check, if the device has a configured documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.hasFirmwareUrl">hasFirmwareUrl</a></td>
-<td>Public method to check, if the device has a configured firmware download URL.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
-<td>Public method to check, if the device has its own flash menu entry.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.hasTimeCommands">hasTimeCommands</a></td>
-<td>Public method to check, if the device supports time commands.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.selectDeviceDirectory">selectDeviceDirectory</a></td>
-<td>Public method to select the device directory from a list of detected ones.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.sendCommands">sendCommands</a></td>
-<td>Public method to send a list of commands to the device.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.setConnected">setConnected</a></td>
-<td>Public method to set the connection state.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.setFileManager">setFileManager</a></td>
-<td>Public method to set the File Manager status and dependent status.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.setPlotter">setPlotter</a></td>
-<td>Public method to set the Plotter status and dependent status.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.setRepl">setRepl</a></td>
-<td>Public method to set the REPL status and dependent status.</td>
-</tr>
-<tr>
-<td><a href="#MicroPythonDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
-<td>Public method to indicate file access via a local directory.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="MicroPythonDevice.__init__" ID="MicroPythonDevice.__init__"></a>
-<h4>MicroPythonDevice (Constructor)</h4>
-<b>MicroPythonDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.addDeviceMenuEntries" ID="MicroPythonDevice.addDeviceMenuEntries"></a>
-<h4>MicroPythonDevice.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.canRunScript" ID="MicroPythonDevice.canRunScript"></a>
-<h4>MicroPythonDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.canStartFileManager" ID="MicroPythonDevice.canStartFileManager"></a>
-<h4>MicroPythonDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.canStartPlotter" ID="MicroPythonDevice.canStartPlotter"></a>
-<h4>MicroPythonDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.canStartRepl" ID="MicroPythonDevice.canStartRepl"></a>
-<h4>MicroPythonDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.checkDeviceData" ID="MicroPythonDevice.checkDeviceData"></a>
-<h4>MicroPythonDevice.checkDeviceData</h4>
-<b>checkDeviceData</b>(<i></i>)
-
-<p>
-        Public method to check the validity of the device data determined during
-        connecting the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating valid device data
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.deviceName" ID="MicroPythonDevice.deviceName"></a>
-<h4>MicroPythonDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.downloadFirmware" ID="MicroPythonDevice.downloadFirmware"></a>
-<h4>MicroPythonDevice.downloadFirmware</h4>
-<b>downloadFirmware</b>(<i></i>)
-
-<p>
-        Public method to download the device firmware.
-</p>
-<a NAME="MicroPythonDevice.forceInterrupt" ID="MicroPythonDevice.forceInterrupt"></a>
-<h4>MicroPythonDevice.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.getDeviceData" ID="MicroPythonDevice.getDeviceData"></a>
-<h4>MicroPythonDevice.getDeviceData</h4>
-<b>getDeviceData</b>(<i></i>)
-
-<p>
-        Public method to get a copy of the determined device data.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-dictionary containing the essential device data
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-dict
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.getDeviceType" ID="MicroPythonDevice.getDeviceType"></a>
-<h4>MicroPythonDevice.getDeviceType</h4>
-<b>getDeviceType</b>(<i></i>)
-
-<p>
-        Public method to get the device type.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-type of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.getDocumentationUrl" ID="MicroPythonDevice.getDocumentationUrl"></a>
-<h4>MicroPythonDevice.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.getDownloadMenuEntries" ID="MicroPythonDevice.getDownloadMenuEntries"></a>
-<h4>MicroPythonDevice.getDownloadMenuEntries</h4>
-<b>getDownloadMenuEntries</b>(<i></i>)
-
-<p>
-        Public method to retrieve the entries for the downloads menu.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of tuples with menu text and URL to be opened for each
-            entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-list of tuple of (str, str)
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.getFirmwareUrl" ID="MicroPythonDevice.getFirmwareUrl"></a>
-<h4>MicroPythonDevice.getFirmwareUrl</h4>
-<b>getFirmwareUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device firmware download URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-firmware download URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.getWorkspace" ID="MicroPythonDevice.getWorkspace"></a>
-<h4>MicroPythonDevice.getWorkspace</h4>
-<b>getWorkspace</b>(<i></i>)
-
-<p>
-        Public method to get the workspace directory.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.handleDataFlood" ID="MicroPythonDevice.handleDataFlood"></a>
-<h4>MicroPythonDevice.handleDataFlood</h4>
-<b>handleDataFlood</b>(<i></i>)
-
-<p>
-        Public slot handling a data floof from the device.
-</p>
-<a NAME="MicroPythonDevice.hasDocumentationUrl" ID="MicroPythonDevice.hasDocumentationUrl"></a>
-<h4>MicroPythonDevice.hasDocumentationUrl</h4>
-<b>hasDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has a configured documentation
-        URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a configured documentation URL
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.hasFirmwareUrl" ID="MicroPythonDevice.hasFirmwareUrl"></a>
-<h4>MicroPythonDevice.hasFirmwareUrl</h4>
-<b>hasFirmwareUrl</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has a configured firmware
-        download URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a configured firmware download URL
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.hasFlashMenuEntry" ID="MicroPythonDevice.hasFlashMenuEntry"></a>
-<h4>MicroPythonDevice.hasFlashMenuEntry</h4>
-<b>hasFlashMenuEntry</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has its own flash menu entry.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a specific flash menu entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.hasTimeCommands" ID="MicroPythonDevice.hasTimeCommands"></a>
-<h4>MicroPythonDevice.hasTimeCommands</h4>
-<b>hasTimeCommands</b>(<i></i>)
-
-<p>
-        Public method to check, if the device supports time commands.
-</p>
-<p>
-        The default returns True.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating support for time commands
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.runScript" ID="MicroPythonDevice.runScript"></a>
-<h4>MicroPythonDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.selectDeviceDirectory" ID="MicroPythonDevice.selectDeviceDirectory"></a>
-<h4>MicroPythonDevice.selectDeviceDirectory</h4>
-<b>selectDeviceDirectory</b>(<i>deviceDirectories</i>)
-
-<p>
-        Public method to select the device directory from a list of detected
-        ones.
-</p>
-<dl>
-
-<dt><i>deviceDirectories</i> (list of str)</dt>
-<dd>
-list of directories to select from
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-selected directory or an empty string
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.sendCommands" ID="MicroPythonDevice.sendCommands"></a>
-<h4>MicroPythonDevice.sendCommands</h4>
-<b>sendCommands</b>(<i>commandsList</i>)
-
-<p>
-        Public method to send a list of commands to the device.
-</p>
-<dl>
-
-<dt><i>commandsList</i> (list of str)</dt>
-<dd>
-list of commands to be sent to the device
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.setButtons" ID="MicroPythonDevice.setButtons"></a>
-<h4>MicroPythonDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<a NAME="MicroPythonDevice.setConnected" ID="MicroPythonDevice.setConnected"></a>
-<h4>MicroPythonDevice.setConnected</h4>
-<b>setConnected</b>(<i>connected</i>)
-
-<p>
-        Public method to set the connection state.
-</p>
-<p>
-        Note: This method can be overwritten to perform actions upon connect
-        or disconnect of the device.
-</p>
-<dl>
-
-<dt><i>connected</i> (bool)</dt>
-<dd>
-connection state
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.setFileManager" ID="MicroPythonDevice.setFileManager"></a>
-<h4>MicroPythonDevice.setFileManager</h4>
-<b>setFileManager</b>(<i>on</i>)
-
-<p>
-        Public method to set the File Manager status and dependent status.
-</p>
-<dl>
-
-<dt><i>on</i> (bool)</dt>
-<dd>
-flag indicating the active status
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.setPlotter" ID="MicroPythonDevice.setPlotter"></a>
-<h4>MicroPythonDevice.setPlotter</h4>
-<b>setPlotter</b>(<i>on</i>)
-
-<p>
-        Public method to set the Plotter status and dependent status.
-</p>
-<dl>
-
-<dt><i>on</i> (bool)</dt>
-<dd>
-flag indicating the active status
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.setRepl" ID="MicroPythonDevice.setRepl"></a>
-<h4>MicroPythonDevice.setRepl</h4>
-<b>setRepl</b>(<i>on</i>)
-
-<p>
-        Public method to set the REPL status and dependent status.
-</p>
-<dl>
-
-<dt><i>on</i> (bool)</dt>
-<dd>
-flag indicating the active status
-</dd>
-</dl>
-<a NAME="MicroPythonDevice.supportsLocalFileAccess" ID="MicroPythonDevice.supportsLocalFileAccess"></a>
-<h4>MicroPythonDevice.supportsLocalFileAccess</h4>
-<b>supportsLocalFileAccess</b>(<i></i>)
-
-<p>
-        Public method to indicate file access via a local directory.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating file access via local directory
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="getDevice" ID="getDevice"></a>
-<h2>getDevice</h2>
-<b>getDevice</b>(<i>deviceType, microPythonWidget, vid, pid, boardName="", serialNumber=""</i>)
-
-<p>
-    Public method to instantiate a specific MicroPython device interface.
-</p>
-<dl>
-
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-type of the device interface
-</dd>
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID (only used for deviceType 'generic')
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID (only used for deviceType 'generic')
-</dd>
-<dt><i>boardName</i> (str (optional))</dt>
-<dd>
-name of the board (defaults to "")
-</dd>
-<dt><i>serialNumber</i> (str (optional))</dt>
-<dd>
-serial number of the board (defaults to "")
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-instantiated device interface
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-MicroPythonDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="getDeviceIcon" ID="getDeviceIcon"></a>
-<h2>getDeviceIcon</h2>
-<b>getDeviceIcon</b>(<i>boardName, iconFormat=True</i>)
-
-<p>
-    Function to get the icon for the given board.
-</p>
-<dl>
-
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>iconFormat</i> (bool)</dt>
-<dd>
-flag indicating to get an icon or a pixmap
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-icon for the board (iconFormat == True) or
-        a pixmap (iconFormat == False)
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-QIcon or QPixmap
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="getFoundDevices" ID="getFoundDevices"></a>
-<h2>getFoundDevices</h2>
-<b>getFoundDevices</b>(<i></i>)
-
-<p>
-    Function to check the serial ports for supported MicroPython devices.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a list of tuples with the board type, the port
-        description, a description, the serial port it is connected at, the
-        VID and PID for known device types, a list of tuples with VID, PID
-        and description for unknown devices and a list of tuples with VID,
-        PID, description and port name for ports with missing VID or PID
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (list of tuples of (str, str, str, str, int, int),
-        list of tuples of (int, int, str),
-        list of tuples of (int, int, str, str)
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="getSupportedDevices" ID="getSupportedDevices"></a>
-<h2>getSupportedDevices</h2>
-<b>getSupportedDevices</b>(<i></i>)
-
-<p>
-    Function to get a list of supported MicroPython devices.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-set of tuples with the board type and description
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-set of tuples of (str, str)
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.MicrobitDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,607 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.MicrobitDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.MicrobitDevices</h1>
-
-<p>
-Module implementing the device interface class for BBC micro:bit and
-Calliope mini boards.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#MicrobitDevice">MicrobitDevice</a></td>
-<td>Class implementing the device for BBC micro:bit and Calliope mini boards.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="MicrobitDevice" ID="MicrobitDevice"></a>
-<h2>MicrobitDevice</h2>
-
-<p>
-    Class implementing the device for BBC micro:bit and Calliope mini boards.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#MicrobitDevice.__init__">MicrobitDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__createMicrobitMenu">__createMicrobitMenu</a></td>
-<td>Private method to create the microbit submenu.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
-<td>Private method handling the response of the latest version request.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__flashMicroPython">__flashMicroPython</a></td>
-<td>Private slot to flash MicroPython or the DAPLink firmware to the device.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__isCalliope">__isCalliope</a></td>
-<td>Private method to check, if the device is a Calliope mini.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__isMicroBitV1">__isMicroBitV1</a></td>
-<td>Private method to check, if the device is a BBC micro:bit v1.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__isMicroBitV2">__isMicroBitV2</a></td>
-<td>Private method to check, if the device is a BBC micro:bit v2.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__resetDevice">__resetDevice</a></td>
-<td>Private slot to reset the connected device.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__saveMain">__saveMain</a></td>
-<td>Private slot to copy the current script as 'main.py' onto the connected device.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__saveScriptToDevice">__saveScriptToDevice</a></td>
-<td>Private method to save the current script onto the connected device.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
-<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
-<td>Public method to retrieve the entries for the downloads menu.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
-<td>Public method to check, if the device has its own flash menu entry.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.hasTimeCommands">hasTimeCommands</a></td>
-<td>Public method to check, if the device supports time commands.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#MicrobitDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="MicrobitDevice.__init__" ID="MicrobitDevice.__init__"></a>
-<h4>MicrobitDevice (Constructor)</h4>
-<b>MicrobitDevice</b>(<i>microPythonWidget, deviceType, serialNumber, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-type of the device
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__createMicrobitMenu" ID="MicrobitDevice.__createMicrobitMenu"></a>
-<h4>MicrobitDevice.__createMicrobitMenu</h4>
-<b>__createMicrobitMenu</b>(<i></i>)
-
-<p>
-        Private method to create the microbit submenu.
-</p>
-<a NAME="MicrobitDevice.__firmwareVersionResponse" ID="MicrobitDevice.__firmwareVersionResponse"></a>
-<h4>MicrobitDevice.__firmwareVersionResponse</h4>
-<b>__firmwareVersionResponse</b>(<i>reply</i>)
-
-<p>
-        Private method handling the response of the latest version request.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the reply object
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__flashMicroPython" ID="MicrobitDevice.__flashMicroPython"></a>
-<h4>MicrobitDevice.__flashMicroPython</h4>
-<b>__flashMicroPython</b>(<i>firmware=False</i>)
-
-<p>
-        Private slot to flash MicroPython or the DAPLink firmware to the
-        device.
-</p>
-<dl>
-
-<dt><i>firmware</i> (bool)</dt>
-<dd>
-flag indicating to flash the DAPLink firmware
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__isCalliope" ID="MicrobitDevice.__isCalliope"></a>
-<h4>MicrobitDevice.__isCalliope</h4>
-<b>__isCalliope</b>(<i></i>)
-
-<p>
-        Private method to check, if the device is a Calliope mini.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a Calliope mini
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__isMicroBitV1" ID="MicrobitDevice.__isMicroBitV1"></a>
-<h4>MicrobitDevice.__isMicroBitV1</h4>
-<b>__isMicroBitV1</b>(<i></i>)
-
-<p>
-        Private method to check, if the device is a BBC micro:bit v1.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-falg indicating a BBC micro:bit v1
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__isMicroBitV2" ID="MicrobitDevice.__isMicroBitV2"></a>
-<h4>MicrobitDevice.__isMicroBitV2</h4>
-<b>__isMicroBitV2</b>(<i></i>)
-
-<p>
-        Private method to check, if the device is a BBC micro:bit v2.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-falg indicating a BBC micro:bit v2
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__resetDevice" ID="MicrobitDevice.__resetDevice"></a>
-<h4>MicrobitDevice.__resetDevice</h4>
-<b>__resetDevice</b>(<i></i>)
-
-<p>
-        Private slot to reset the connected device.
-</p>
-<a NAME="MicrobitDevice.__saveMain" ID="MicrobitDevice.__saveMain"></a>
-<h4>MicrobitDevice.__saveMain</h4>
-<b>__saveMain</b>(<i></i>)
-
-<p>
-        Private slot to copy the current script as 'main.py' onto the
-        connected device.
-</p>
-<a NAME="MicrobitDevice.__saveScriptToDevice" ID="MicrobitDevice.__saveScriptToDevice"></a>
-<h4>MicrobitDevice.__saveScriptToDevice</h4>
-<b>__saveScriptToDevice</b>(<i>scriptName=""</i>)
-
-<p>
-        Private method to save the current script onto the connected
-        device.
-</p>
-<dl>
-
-<dt><i>scriptName</i> (str)</dt>
-<dd>
-name of the file on the device
-</dd>
-</dl>
-<a NAME="MicrobitDevice.__showFirmwareVersions" ID="MicrobitDevice.__showFirmwareVersions"></a>
-<h4>MicrobitDevice.__showFirmwareVersions</h4>
-<b>__showFirmwareVersions</b>(<i></i>)
-
-<p>
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-</p>
-<a NAME="MicrobitDevice.addDeviceMenuEntries" ID="MicrobitDevice.addDeviceMenuEntries"></a>
-<h4>MicrobitDevice.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="MicrobitDevice.canRunScript" ID="MicrobitDevice.canRunScript"></a>
-<h4>MicrobitDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicrobitDevice.canStartFileManager" ID="MicrobitDevice.canStartFileManager"></a>
-<h4>MicrobitDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicrobitDevice.canStartPlotter" ID="MicrobitDevice.canStartPlotter"></a>
-<h4>MicrobitDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicrobitDevice.canStartRepl" ID="MicrobitDevice.canStartRepl"></a>
-<h4>MicrobitDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="MicrobitDevice.deviceName" ID="MicrobitDevice.deviceName"></a>
-<h4>MicrobitDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicrobitDevice.forceInterrupt" ID="MicrobitDevice.forceInterrupt"></a>
-<h4>MicrobitDevice.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicrobitDevice.getDocumentationUrl" ID="MicrobitDevice.getDocumentationUrl"></a>
-<h4>MicrobitDevice.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="MicrobitDevice.getDownloadMenuEntries" ID="MicrobitDevice.getDownloadMenuEntries"></a>
-<h4>MicrobitDevice.getDownloadMenuEntries</h4>
-<b>getDownloadMenuEntries</b>(<i></i>)
-
-<p>
-        Public method to retrieve the entries for the downloads menu.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of tuples with menu text and URL to be opened for each
-            entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-list of tuple of (str, str)
-</dd>
-</dl>
-<a NAME="MicrobitDevice.hasFlashMenuEntry" ID="MicrobitDevice.hasFlashMenuEntry"></a>
-<h4>MicrobitDevice.hasFlashMenuEntry</h4>
-<b>hasFlashMenuEntry</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has its own flash menu entry.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a specific flash menu entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicrobitDevice.hasTimeCommands" ID="MicrobitDevice.hasTimeCommands"></a>
-<h4>MicrobitDevice.hasTimeCommands</h4>
-<b>hasTimeCommands</b>(<i></i>)
-
-<p>
-        Public method to check, if the device supports time commands.
-</p>
-<p>
-        The default returns True.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating support for time commands
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="MicrobitDevice.runScript" ID="MicrobitDevice.runScript"></a>
-<h4>MicrobitDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="MicrobitDevice.setButtons" ID="MicrobitDevice.setButtons"></a>
-<h4>MicrobitDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-MicrobitDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.PyBoardDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,660 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.PyBoardDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.PyBoardDevices</h1>
-
-<p>
-Module implementing the device interface class for PyBoard boards.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#PyBoardDevice">PyBoardDevice</a></td>
-<td>Class implementing the device for PyBoard boards.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="PyBoardDevice" ID="PyBoardDevice"></a>
-<h2>PyBoardDevice</h2>
-
-<p>
-    Class implementing the device for PyBoard boards.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>DeviceVolumeName</td></tr><tr><td>FlashInstructionsURL</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#PyBoardDevice.__init__">PyBoardDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__activateBootloader">__activateBootloader</a></td>
-<td>Private slot to activate the bootloader and disconnect.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__createPyboardMenu">__createPyboardMenu</a></td>
-<td>Private method to create the pyboard submenu.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td>
-<td>Private method to check, if the device volume is mounted.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__dfuUtilAvailable">__dfuUtilAvailable</a></td>
-<td>Private method to check the availability of dfu-util.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__findWorkspace">__findWorkspace</a></td>
-<td>Private method to find the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
-<td>Private method handling the response of the latest version request.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__flashMicroPython">__flashMicroPython</a></td>
-<td>Private slot to flash a MicroPython firmware.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__listDfuCapableDevices">__listDfuCapableDevices</a></td>
-<td>Private slot to list all DFU-capable devices.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__showDfuDisableInstructions">__showDfuDisableInstructions</a></td>
-<td>Private method to show some instructions to disable the DFU mode.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__showDfuEnableInstructions">__showDfuEnableInstructions</a></td>
-<td>Private method to show some instructions to enable the DFU mode.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
-<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.__showFlashInstructions">__showFlashInstructions</a></td>
-<td>Private slot to open the URL containing instructions for installing MicroPython on the pyboard.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.getFirmwareUrl">getFirmwareUrl</a></td>
-<td>Public method to get the device firmware download URL.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.getWorkspace">getWorkspace</a></td>
-<td>Public method to get the workspace directory.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
-<td>Public method to check, if the device has its own flash menu entry.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-<tr>
-<td><a href="#PyBoardDevice.supportsLocalFileAccess">supportsLocalFileAccess</a></td>
-<td>Public method to indicate file access via a local directory.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="PyBoardDevice.__init__" ID="PyBoardDevice.__init__"></a>
-<h4>PyBoardDevice (Constructor)</h4>
-<b>PyBoardDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="PyBoardDevice.__activateBootloader" ID="PyBoardDevice.__activateBootloader"></a>
-<h4>PyBoardDevice.__activateBootloader</h4>
-<b>__activateBootloader</b>(<i></i>)
-
-<p>
-        Private slot to activate the bootloader and disconnect.
-</p>
-<a NAME="PyBoardDevice.__createPyboardMenu" ID="PyBoardDevice.__createPyboardMenu"></a>
-<h4>PyBoardDevice.__createPyboardMenu</h4>
-<b>__createPyboardMenu</b>(<i></i>)
-
-<p>
-        Private method to create the pyboard submenu.
-</p>
-<a NAME="PyBoardDevice.__deviceVolumeMounted" ID="PyBoardDevice.__deviceVolumeMounted"></a>
-<h4>PyBoardDevice.__deviceVolumeMounted</h4>
-<b>__deviceVolumeMounted</b>(<i></i>)
-
-<p>
-        Private method to check, if the device volume is mounted.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicated a mounted device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="PyBoardDevice.__dfuUtilAvailable" ID="PyBoardDevice.__dfuUtilAvailable"></a>
-<h4>PyBoardDevice.__dfuUtilAvailable</h4>
-<b>__dfuUtilAvailable</b>(<i></i>)
-
-<p>
-        Private method to check the availability of dfu-util.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating the availability of dfu-util
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="PyBoardDevice.__findWorkspace" ID="PyBoardDevice.__findWorkspace"></a>
-<h4>PyBoardDevice.__findWorkspace</h4>
-<b>__findWorkspace</b>(<i>silent=False</i>)
-
-<p>
-        Private method to find the workspace directory.
-</p>
-<dl>
-
-<dt><i>silent</i> (bool)</dt>
-<dd>
-flag indicating silent operations
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="PyBoardDevice.__firmwareVersionResponse" ID="PyBoardDevice.__firmwareVersionResponse"></a>
-<h4>PyBoardDevice.__firmwareVersionResponse</h4>
-<b>__firmwareVersionResponse</b>(<i>reply</i>)
-
-<p>
-        Private method handling the response of the latest version request.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the reply object
-</dd>
-</dl>
-<a NAME="PyBoardDevice.__flashMicroPython" ID="PyBoardDevice.__flashMicroPython"></a>
-<h4>PyBoardDevice.__flashMicroPython</h4>
-<b>__flashMicroPython</b>(<i></i>)
-
-<p>
-        Private slot to flash a MicroPython firmware.
-</p>
-<a NAME="PyBoardDevice.__listDfuCapableDevices" ID="PyBoardDevice.__listDfuCapableDevices"></a>
-<h4>PyBoardDevice.__listDfuCapableDevices</h4>
-<b>__listDfuCapableDevices</b>(<i></i>)
-
-<p>
-        Private slot to list all DFU-capable devices.
-</p>
-<a NAME="PyBoardDevice.__showDfuDisableInstructions" ID="PyBoardDevice.__showDfuDisableInstructions"></a>
-<h4>PyBoardDevice.__showDfuDisableInstructions</h4>
-<b>__showDfuDisableInstructions</b>(<i></i>)
-
-<p>
-        Private method to show some instructions to disable the DFU mode.
-</p>
-<a NAME="PyBoardDevice.__showDfuEnableInstructions" ID="PyBoardDevice.__showDfuEnableInstructions"></a>
-<h4>PyBoardDevice.__showDfuEnableInstructions</h4>
-<b>__showDfuEnableInstructions</b>(<i>flash=True</i>)
-
-<p>
-        Private method to show some instructions to enable the DFU mode.
-</p>
-<dl>
-
-<dt><i>flash</i> (bool)</dt>
-<dd>
-flag indicating to show a warning message for flashing
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating OK to continue or abort
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="PyBoardDevice.__showFirmwareVersions" ID="PyBoardDevice.__showFirmwareVersions"></a>
-<h4>PyBoardDevice.__showFirmwareVersions</h4>
-<b>__showFirmwareVersions</b>(<i></i>)
-
-<p>
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-</p>
-<a NAME="PyBoardDevice.__showFlashInstructions" ID="PyBoardDevice.__showFlashInstructions"></a>
-<h4>PyBoardDevice.__showFlashInstructions</h4>
-<b>__showFlashInstructions</b>(<i></i>)
-
-<p>
-        Private slot to open the URL containing instructions for installing
-        MicroPython on the pyboard.
-</p>
-<a NAME="PyBoardDevice.addDeviceMenuEntries" ID="PyBoardDevice.addDeviceMenuEntries"></a>
-<h4>PyBoardDevice.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="PyBoardDevice.canRunScript" ID="PyBoardDevice.canRunScript"></a>
-<h4>PyBoardDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="PyBoardDevice.canStartFileManager" ID="PyBoardDevice.canStartFileManager"></a>
-<h4>PyBoardDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="PyBoardDevice.canStartPlotter" ID="PyBoardDevice.canStartPlotter"></a>
-<h4>PyBoardDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="PyBoardDevice.canStartRepl" ID="PyBoardDevice.canStartRepl"></a>
-<h4>PyBoardDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="PyBoardDevice.deviceName" ID="PyBoardDevice.deviceName"></a>
-<h4>PyBoardDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="PyBoardDevice.forceInterrupt" ID="PyBoardDevice.forceInterrupt"></a>
-<h4>PyBoardDevice.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="PyBoardDevice.getDocumentationUrl" ID="PyBoardDevice.getDocumentationUrl"></a>
-<h4>PyBoardDevice.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="PyBoardDevice.getFirmwareUrl" ID="PyBoardDevice.getFirmwareUrl"></a>
-<h4>PyBoardDevice.getFirmwareUrl</h4>
-<b>getFirmwareUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device firmware download URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-firmware download URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="PyBoardDevice.getWorkspace" ID="PyBoardDevice.getWorkspace"></a>
-<h4>PyBoardDevice.getWorkspace</h4>
-<b>getWorkspace</b>(<i>silent=False</i>)
-
-<p>
-        Public method to get the workspace directory.
-</p>
-<dl>
-
-<dt><i>silent</i> (bool)</dt>
-<dd>
-flag indicating silent operations
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-workspace directory used for saving files
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="PyBoardDevice.hasFlashMenuEntry" ID="PyBoardDevice.hasFlashMenuEntry"></a>
-<h4>PyBoardDevice.hasFlashMenuEntry</h4>
-<b>hasFlashMenuEntry</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has its own flash menu entry.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a specific flash menu entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="PyBoardDevice.runScript" ID="PyBoardDevice.runScript"></a>
-<h4>PyBoardDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="PyBoardDevice.setButtons" ID="PyBoardDevice.setButtons"></a>
-<h4>PyBoardDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<a NAME="PyBoardDevice.supportsLocalFileAccess" ID="PyBoardDevice.supportsLocalFileAccess"></a>
-<h4>PyBoardDevice.supportsLocalFileAccess</h4>
-<b>supportsLocalFileAccess</b>(<i></i>)
-
-<p>
-        Public method to indicate file access via a local directory.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating file access via local directory
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-PyBoardDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.RP2040Devices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,469 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.RP2040Devices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.RP2040Devices</h1>
-
-<p>
-Module implementing the device interface class for RP2040 based boards
-(e.g. Raspberry Pi Pico).
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#RP2040Device">RP2040Device</a></td>
-<td>Class implementing the device for RP2040 based boards.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="RP2040Device" ID="RP2040Device"></a>
-<h2>RP2040Device</h2>
-
-<p>
-    Class implementing the device for RP2040 based boards.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#RP2040Device.__init__">RP2040Device</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.__activateBootloader">__activateBootloader</a></td>
-<td>Private method to switch the board into 'bootloader' mode.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.__createRP2040Menu">__createRP2040Menu</a></td>
-<td>Private method to create the RO2040 submenu.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
-<td>Private method handling the response of the latest version request.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.__flashPython">__flashPython</a></td>
-<td>Private slot to flash a MicroPython firmware to the device.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.__showFirmwareVersions">__showFirmwareVersions</a></td>
-<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.getDownloadMenuEntries">getDownloadMenuEntries</a></td>
-<td>Public method to retrieve the entries for the downloads menu.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.hasFlashMenuEntry">hasFlashMenuEntry</a></td>
-<td>Public method to check, if the device has its own flash menu entry.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#RP2040Device.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="RP2040Device.__init__" ID="RP2040Device.__init__"></a>
-<h4>RP2040Device (Constructor)</h4>
-<b>RP2040Device</b>(<i>microPythonWidget, deviceType, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="RP2040Device.__activateBootloader" ID="RP2040Device.__activateBootloader"></a>
-<h4>RP2040Device.__activateBootloader</h4>
-<b>__activateBootloader</b>(<i></i>)
-
-<p>
-        Private method to switch the board into 'bootloader' mode.
-</p>
-<a NAME="RP2040Device.__createRP2040Menu" ID="RP2040Device.__createRP2040Menu"></a>
-<h4>RP2040Device.__createRP2040Menu</h4>
-<b>__createRP2040Menu</b>(<i></i>)
-
-<p>
-        Private method to create the RO2040 submenu.
-</p>
-<a NAME="RP2040Device.__firmwareVersionResponse" ID="RP2040Device.__firmwareVersionResponse"></a>
-<h4>RP2040Device.__firmwareVersionResponse</h4>
-<b>__firmwareVersionResponse</b>(<i>reply</i>)
-
-<p>
-        Private method handling the response of the latest version request.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the reply object
-</dd>
-</dl>
-<a NAME="RP2040Device.__flashPython" ID="RP2040Device.__flashPython"></a>
-<h4>RP2040Device.__flashPython</h4>
-<b>__flashPython</b>(<i></i>)
-
-<p>
-        Private slot to flash a MicroPython firmware to the device.
-</p>
-<a NAME="RP2040Device.__showFirmwareVersions" ID="RP2040Device.__showFirmwareVersions"></a>
-<h4>RP2040Device.__showFirmwareVersions</h4>
-<b>__showFirmwareVersions</b>(<i></i>)
-
-<p>
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-</p>
-<a NAME="RP2040Device.addDeviceMenuEntries" ID="RP2040Device.addDeviceMenuEntries"></a>
-<h4>RP2040Device.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="RP2040Device.canRunScript" ID="RP2040Device.canRunScript"></a>
-<h4>RP2040Device.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="RP2040Device.canStartFileManager" ID="RP2040Device.canStartFileManager"></a>
-<h4>RP2040Device.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="RP2040Device.canStartPlotter" ID="RP2040Device.canStartPlotter"></a>
-<h4>RP2040Device.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="RP2040Device.canStartRepl" ID="RP2040Device.canStartRepl"></a>
-<h4>RP2040Device.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="RP2040Device.deviceName" ID="RP2040Device.deviceName"></a>
-<h4>RP2040Device.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="RP2040Device.forceInterrupt" ID="RP2040Device.forceInterrupt"></a>
-<h4>RP2040Device.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="RP2040Device.getDocumentationUrl" ID="RP2040Device.getDocumentationUrl"></a>
-<h4>RP2040Device.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="RP2040Device.getDownloadMenuEntries" ID="RP2040Device.getDownloadMenuEntries"></a>
-<h4>RP2040Device.getDownloadMenuEntries</h4>
-<b>getDownloadMenuEntries</b>(<i></i>)
-
-<p>
-        Public method to retrieve the entries for the downloads menu.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-list of tuples with menu text and URL to be opened for each
-            entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-list of tuple of (str, str)
-</dd>
-</dl>
-<a NAME="RP2040Device.hasFlashMenuEntry" ID="RP2040Device.hasFlashMenuEntry"></a>
-<h4>RP2040Device.hasFlashMenuEntry</h4>
-<b>hasFlashMenuEntry</b>(<i></i>)
-
-<p>
-        Public method to check, if the device has its own flash menu entry.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating a specific flash menu entry
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="RP2040Device.runScript" ID="RP2040Device.runScript"></a>
-<h4>RP2040Device.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="RP2040Device.setButtons" ID="RP2040Device.setButtons"></a>
-<h4>RP2040Device.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-RP2040Device
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/eric7.MicroPython.TeensyDevices.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,447 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.TeensyDevices</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<a NAME="top" ID="top"></a>
-<h1>eric7.MicroPython.TeensyDevices</h1>
-
-<p>
-Module implementing the device interface class for Teensy boards with MicroPython.
-</p>
-<h3>Global Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Classes</h3>
-
-<table>
-
-<tr>
-<td><a href="#TeensyDevice">TeensyDevice</a></td>
-<td>Class implementing the device for Teensy boards with MicroPython.</td>
-</tr>
-</table>
-<h3>Functions</h3>
-
-<table>
-
-<tr>
-<td><a href="#createDevice">createDevice</a></td>
-<td>Function to instantiate a MicroPython device object.</td>
-</tr>
-</table>
-<hr />
-<hr />
-<a NAME="TeensyDevice" ID="TeensyDevice"></a>
-<h2>TeensyDevice</h2>
-
-<p>
-    Class implementing the device for Teensy boards with MicroPython.
-</p>
-<h3>Derived from</h3>
-MicroPythonDevice
-<h3>Class Attributes</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Class Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-<h3>Methods</h3>
-
-<table>
-
-<tr>
-<td><a href="#TeensyDevice.__init__">TeensyDevice</a></td>
-<td>Constructor</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.__createTeensyMenu">__createTeensyMenu</a></td>
-<td>Private method to create the microbit submenu.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.__firmwareVersionResponse">__firmwareVersionResponse</a></td>
-<td>Private method handling the response of the latest version request.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.__showFirmwareVersions">__showFirmwareVersions</a></td>
-<td>Private slot to show the firmware version of the connected device and the available firmware version.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.__showFlashInstructions">__showFlashInstructions</a></td>
-<td>Private method to show a message box with instruction to flash the Teensy.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.__startTeensyLoader">__startTeensyLoader</a></td>
-<td>Private method to start the 'Teensy Loader' application.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.addDeviceMenuEntries">addDeviceMenuEntries</a></td>
-<td>Public method to add device specific entries to the given menu.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.canRunScript">canRunScript</a></td>
-<td>Public method to determine, if a script can be executed.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.canStartFileManager">canStartFileManager</a></td>
-<td>Public method to determine, if a File Manager can be started.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.canStartPlotter">canStartPlotter</a></td>
-<td>Public method to determine, if a Plotter can be started.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.canStartRepl">canStartRepl</a></td>
-<td>Public method to determine, if a REPL can be started.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.deviceName">deviceName</a></td>
-<td>Public method to get the name of the device.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.forceInterrupt">forceInterrupt</a></td>
-<td>Public method to determine the need for an interrupt when opening the serial connection.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.getDocumentationUrl">getDocumentationUrl</a></td>
-<td>Public method to get the device documentation URL.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.getFirmwareUrl">getFirmwareUrl</a></td>
-<td>Public method to get the device firmware download URL.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.runScript">runScript</a></td>
-<td>Public method to run the given Python script.</td>
-</tr>
-<tr>
-<td><a href="#TeensyDevice.setButtons">setButtons</a></td>
-<td>Public method to enable the supported action buttons.</td>
-</tr>
-</table>
-<h3>Static Methods</h3>
-
-<table>
-<tr><td>None</td></tr>
-</table>
-
-<a NAME="TeensyDevice.__init__" ID="TeensyDevice.__init__"></a>
-<h4>TeensyDevice (Constructor)</h4>
-<b>TeensyDevice</b>(<i>microPythonWidget, deviceType, parent=None</i>)
-
-<p>
-        Constructor
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>parent</i> (QObject)</dt>
-<dd>
-reference to the parent object
-</dd>
-</dl>
-<a NAME="TeensyDevice.__createTeensyMenu" ID="TeensyDevice.__createTeensyMenu"></a>
-<h4>TeensyDevice.__createTeensyMenu</h4>
-<b>__createTeensyMenu</b>(<i></i>)
-
-<p>
-        Private method to create the microbit submenu.
-</p>
-<a NAME="TeensyDevice.__firmwareVersionResponse" ID="TeensyDevice.__firmwareVersionResponse"></a>
-<h4>TeensyDevice.__firmwareVersionResponse</h4>
-<b>__firmwareVersionResponse</b>(<i>reply</i>)
-
-<p>
-        Private method handling the response of the latest version request.
-</p>
-<dl>
-
-<dt><i>reply</i> (QNetworkReply)</dt>
-<dd>
-reference to the reply object
-</dd>
-</dl>
-<a NAME="TeensyDevice.__showFirmwareVersions" ID="TeensyDevice.__showFirmwareVersions"></a>
-<h4>TeensyDevice.__showFirmwareVersions</h4>
-<b>__showFirmwareVersions</b>(<i></i>)
-
-<p>
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-</p>
-<a NAME="TeensyDevice.__showFlashInstructions" ID="TeensyDevice.__showFlashInstructions"></a>
-<h4>TeensyDevice.__showFlashInstructions</h4>
-<b>__showFlashInstructions</b>(<i></i>)
-
-<p>
-        Private method to show a message box with instruction to flash the Teensy.
-</p>
-<a NAME="TeensyDevice.__startTeensyLoader" ID="TeensyDevice.__startTeensyLoader"></a>
-<h4>TeensyDevice.__startTeensyLoader</h4>
-<b>__startTeensyLoader</b>(<i></i>)
-
-<p>
-        Private method to start the 'Teensy Loader' application.
-</p>
-<p>
-        Note: The application must be accessible via the application search path.
-</p>
-<a NAME="TeensyDevice.addDeviceMenuEntries" ID="TeensyDevice.addDeviceMenuEntries"></a>
-<h4>TeensyDevice.addDeviceMenuEntries</h4>
-<b>addDeviceMenuEntries</b>(<i>menu</i>)
-
-<p>
-        Public method to add device specific entries to the given menu.
-</p>
-<dl>
-
-<dt><i>menu</i> (QMenu)</dt>
-<dd>
-reference to the context menu
-</dd>
-</dl>
-<a NAME="TeensyDevice.canRunScript" ID="TeensyDevice.canRunScript"></a>
-<h4>TeensyDevice.canRunScript</h4>
-<b>canRunScript</b>(<i></i>)
-
-<p>
-        Public method to determine, if a script can be executed.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="TeensyDevice.canStartFileManager" ID="TeensyDevice.canStartFileManager"></a>
-<h4>TeensyDevice.canStartFileManager</h4>
-<b>canStartFileManager</b>(<i></i>)
-
-<p>
-        Public method to determine, if a File Manager can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="TeensyDevice.canStartPlotter" ID="TeensyDevice.canStartPlotter"></a>
-<h4>TeensyDevice.canStartPlotter</h4>
-<b>canStartPlotter</b>(<i></i>)
-
-<p>
-        Public method to determine, if a Plotter can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="TeensyDevice.canStartRepl" ID="TeensyDevice.canStartRepl"></a>
-<h4>TeensyDevice.canStartRepl</h4>
-<b>canStartRepl</b>(<i></i>)
-
-<p>
-        Public method to determine, if a REPL can be started.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-tuple of (bool, str)
-</dd>
-</dl>
-<a NAME="TeensyDevice.deviceName" ID="TeensyDevice.deviceName"></a>
-<h4>TeensyDevice.deviceName</h4>
-<b>deviceName</b>(<i></i>)
-
-<p>
-        Public method to get the name of the device.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-name of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="TeensyDevice.forceInterrupt" ID="TeensyDevice.forceInterrupt"></a>
-<h4>TeensyDevice.forceInterrupt</h4>
-<b>forceInterrupt</b>(<i></i>)
-
-<p>
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-flag indicating an interrupt is needed
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-bool
-</dd>
-</dl>
-<a NAME="TeensyDevice.getDocumentationUrl" ID="TeensyDevice.getDocumentationUrl"></a>
-<h4>TeensyDevice.getDocumentationUrl</h4>
-<b>getDocumentationUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device documentation URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-documentation URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="TeensyDevice.getFirmwareUrl" ID="TeensyDevice.getFirmwareUrl"></a>
-<h4>TeensyDevice.getFirmwareUrl</h4>
-<b>getFirmwareUrl</b>(<i></i>)
-
-<p>
-        Public method to get the device firmware download URL.
-</p>
-<dl>
-<dt>Return:</dt>
-<dd>
-firmware download URL of the device
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-str
-</dd>
-</dl>
-<a NAME="TeensyDevice.runScript" ID="TeensyDevice.runScript"></a>
-<h4>TeensyDevice.runScript</h4>
-<b>runScript</b>(<i>script</i>)
-
-<p>
-        Public method to run the given Python script.
-</p>
-<dl>
-
-<dt><i>script</i> (str)</dt>
-<dd>
-script to be executed
-</dd>
-</dl>
-<a NAME="TeensyDevice.setButtons" ID="TeensyDevice.setButtons"></a>
-<h4>TeensyDevice.setButtons</h4>
-<b>setButtons</b>(<i></i>)
-
-<p>
-        Public method to enable the supported action buttons.
-</p>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-<hr />
-<a NAME="createDevice" ID="createDevice"></a>
-<h2>createDevice</h2>
-<b>createDevice</b>(<i>microPythonWidget, deviceType, vid, pid, boardName, serialNumber</i>)
-
-<p>
-    Function to instantiate a MicroPython device object.
-</p>
-<dl>
-
-<dt><i>microPythonWidget</i> (MicroPythonWidget)</dt>
-<dd>
-reference to the main MicroPython widget
-</dd>
-<dt><i>deviceType</i> (str)</dt>
-<dd>
-device type assigned to this device interface
-</dd>
-<dt><i>vid</i> (int)</dt>
-<dd>
-vendor ID
-</dd>
-<dt><i>pid</i> (int)</dt>
-<dd>
-product ID
-</dd>
-<dt><i>boardName</i> (str)</dt>
-<dd>
-name of the board
-</dd>
-<dt><i>serialNumber</i> (str)</dt>
-<dd>
-serial number of the board
-</dd>
-</dl>
-<dl>
-<dt>Return:</dt>
-<dd>
-reference to the instantiated device object
-</dd>
-</dl>
-<dl>
-<dt>Return Type:</dt>
-<dd>
-PyBoardDevice
-</dd>
-</dl>
-<div align="right"><a href="#top">Up</a></div>
-<hr />
-</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/index-eric7.MicroPython.CircuitPythonUpdater.html	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<html><head>
-<title>eric7.MicroPython.CircuitPythonUpdater</title>
-<meta charset="UTF-8">
-<link rel="stylesheet" href="styles.css">
-</head>
-<body>
-<h1>eric7.MicroPython.CircuitPythonUpdater</h1>
-
-<p>
-Package implementing the updater and associated dialogs.
-</p>
-
-
-<h3>Modules</h3>
-<table>
-
-<tr>
-<td><a href="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html">CircuitPythonUpdaterInterface</a></td>
-<td>Module implementing an interface to the 'circup' package.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html">CircupFunctions</a></td>
-<td>Module implementing variants of some 'circup' functions suitable for 'eric-ide' integration.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html">RequirementsDialog</a></td>
-<td>Module implementing a dialog to generate a requirements file.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html">ShowBundlesDialog</a></td>
-<td>Module implementing a dialog showing the available bundles and their modules.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html">ShowInstalledDialog</a></td>
-<td>Module implementing a dialog to show the modules installed on the connected device.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html">ShowOutdatedDialog</a></td>
-<td>Module implementing a dialog to show outdated modules of a connected device.</td>
-</tr>
-</table>
-</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/index-eric7.MicroPython.Devices.CircuitPythonUpdater.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.CircuitPythonUpdater</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<h1>eric7.MicroPython.Devices.CircuitPythonUpdater</h1>
+
+<p>
+Package implementing the updater and associated dialogs.
+</p>
+
+
+<h3>Modules</h3>
+<table>
+
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html">CircuitPythonUpdaterInterface</a></td>
+<td>Module implementing an interface to the 'circup' package.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonUpdater.CircupFunctions.html">CircupFunctions</a></td>
+<td>Module implementing variants of some 'circup' functions suitable for 'eric-ide' integration.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonUpdater.RequirementsDialog.html">RequirementsDialog</a></td>
+<td>Module implementing a dialog to generate a requirements file.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowBundlesDialog.html">ShowBundlesDialog</a></td>
+<td>Module implementing a dialog showing the available bundles and their modules.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowInstalledDialog.html">ShowInstalledDialog</a></td>
+<td>Module implementing a dialog to show the modules installed on the connected device.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonUpdater.ShowOutdatedDialog.html">ShowOutdatedDialog</a></td>
+<td>Module implementing a dialog to show outdated modules of a connected device.</td>
+</tr>
+</table>
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/index-eric7.MicroPython.Devices.EspDialogs.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices.EspDialogs</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<h1>eric7.MicroPython.Devices.EspDialogs</h1>
+
+<p>
+Package implementing dialogs used by the EspDevices module.
+</p>
+
+
+<h3>Modules</h3>
+<table>
+
+<tr>
+<td><a href="eric7.MicroPython.Devices.EspDialogs.EspBackupRestoreFirmwareDialog.html">EspBackupRestoreFirmwareDialog</a></td>
+<td>Module implementing a dialog to select the ESP chip type and the backup and restore parameters.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.EspDialogs.EspFirmwareSelectionDialog.html">EspFirmwareSelectionDialog</a></td>
+<td>Module implementing a dialog to select the ESP chip type and the firmware to be flashed.</td>
+</tr>
+</table>
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/Documentation/Source/index-eric7.MicroPython.Devices.html	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric7.MicroPython.Devices</title>
+<meta charset="UTF-8">
+<link rel="stylesheet" href="styles.css">
+</head>
+<body>
+<h1>eric7.MicroPython.Devices</h1>
+
+<p>
+Package containing the device interface modules and device specific dialogs.
+</p>
+
+<h3>Packages</h3>
+<table>
+
+<tr>
+<td><a href="index-eric7.MicroPython.Devices.CircuitPythonUpdater.html">CircuitPythonUpdater</a></td>
+<td>Package implementing the updater and associated dialogs.</td>
+</tr>
+<tr>
+<td><a href="index-eric7.MicroPython.Devices.EspDialogs.html">EspDialogs</a></td>
+<td>Package implementing dialogs used by the EspDevices module.</td>
+</tr>
+</table>
+
+<h3>Modules</h3>
+<table>
+
+<tr>
+<td><a href="eric7.MicroPython.Devices.CircuitPythonDevices.html">CircuitPythonDevices</a></td>
+<td>Module implementing the device interface class for CircuitPython boards.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.DeviceBase.html">DeviceBase</a></td>
+<td>Module implementing some utility functions and the MicroPythonDevice base class.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.EspDevices.html">EspDevices</a></td>
+<td>Module implementing the device interface class for ESP32 and ESP8266 based boards.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.GenericMicroPythonDevices.html">GenericMicroPythonDevices</a></td>
+<td>Module implementing the device interface class for generic MicroPython devices (i.e.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.MicrobitDevices.html">MicrobitDevices</a></td>
+<td>Module implementing the device interface class for BBC micro:bit and Calliope mini boards.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.PyBoardDevices.html">PyBoardDevices</a></td>
+<td>Module implementing the device interface class for PyBoard boards.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.RP2040Devices.html">RP2040Devices</a></td>
+<td>Module implementing the device interface class for RP2040 based boards (e.g.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.TeensyDevices.html">TeensyDevices</a></td>
+<td>Module implementing the device interface class for Teensy boards with MicroPython.</td>
+</tr>
+<tr>
+<td><a href="eric7.MicroPython.Devices.__init__.html">Devices</a></td>
+<td>Package containing the device interface modules and device specific dialogs.</td>
+</tr>
+</table>
+</body></html>
\ No newline at end of file
--- a/src/eric7/Documentation/Source/index-eric7.MicroPython.html	Sun Feb 12 18:11:20 2023 +0100
+++ b/src/eric7/Documentation/Source/index-eric7.MicroPython.html	Mon Feb 13 17:49:52 2023 +0100
@@ -15,8 +15,8 @@
 <table>
 
 <tr>
-<td><a href="index-eric7.MicroPython.CircuitPythonUpdater.html">CircuitPythonUpdater</a></td>
-<td>Package implementing the updater and associated dialogs.</td>
+<td><a href="index-eric7.MicroPython.Devices.html">Devices</a></td>
+<td>Package containing the device interface modules and device specific dialogs.</td>
 </tr>
 </table>
 
@@ -32,30 +32,10 @@
 <td>Module implementing a dialog to show information about a connected board.</td>
 </tr>
 <tr>
-<td><a href="eric7.MicroPython.CircuitPythonDevices.html">CircuitPythonDevices</a></td>
-<td>Module implementing the device interface class for CircuitPython boards.</td>
-</tr>
-<tr>
 <td><a href="eric7.MicroPython.ConnectionSelectionDialog.html">ConnectionSelectionDialog</a></td>
 <td>Module implementing a dialog to select the port to connect to and the type of the attached device.</td>
 </tr>
 <tr>
-<td><a href="eric7.MicroPython.EspBackupRestoreFirmwareDialog.html">EspBackupRestoreFirmwareDialog</a></td>
-<td>Module implementing a dialog to select the ESP chip type and the backup and restore parameters.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.EspDevices.html">EspDevices</a></td>
-<td>Module implementing the device interface class for ESP32 and ESP8266 based boards.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.EspFirmwareSelectionDialog.html">EspFirmwareSelectionDialog</a></td>
-<td>Module implementing a dialog to select the ESP chip type and the firmware to be flashed.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.GenericMicroPythonDevices.html">GenericMicroPythonDevices</a></td>
-<td>Module implementing the device interface class for generic MicroPython devices (i.e.</td>
-</tr>
-<tr>
 <td><a href="eric7.MicroPython.IgnoredDevicesDialog.html">IgnoredDevicesDialog</a></td>
 <td>Module implementing a dialog to manage the list of ignored serial devices.</td>
 </tr>
@@ -64,10 +44,6 @@
 <td>Module implementing some file system commands for MicroPython.</td>
 </tr>
 <tr>
-<td><a href="eric7.MicroPython.MicroPythonDevices.html">MicroPythonDevices</a></td>
-<td>Module implementing some utility functions and the MicroPythonDevice base class.</td>
-</tr>
-<tr>
 <td><a href="eric7.MicroPython.MicroPythonFileManager.html">MicroPythonFileManager</a></td>
 <td>Module implementing some file system commands for MicroPython.</td>
 </tr>
@@ -96,26 +72,10 @@
 <td>Module implementing the MicroPython REPL widget.</td>
 </tr>
 <tr>
-<td><a href="eric7.MicroPython.MicrobitDevices.html">MicrobitDevices</a></td>
-<td>Module implementing the device interface class for BBC micro:bit and Calliope mini boards.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.PyBoardDevices.html">PyBoardDevices</a></td>
-<td>Module implementing the device interface class for PyBoard boards.</td>
-</tr>
-<tr>
-<td><a href="eric7.MicroPython.RP2040Devices.html">RP2040Devices</a></td>
-<td>Module implementing the device interface class for RP2040 based boards (e.g.</td>
-</tr>
-<tr>
 <td><a href="eric7.MicroPython.ShowModulesDialog.html">ShowModulesDialog</a></td>
 <td>Module implementing a dialog to show the available modules of all bundles.</td>
 </tr>
 <tr>
-<td><a href="eric7.MicroPython.TeensyDevices.html">TeensyDevices</a></td>
-<td>Module implementing the device interface class for Teensy boards with MicroPython.</td>
-</tr>
-<tr>
 <td><a href="eric7.MicroPython.UF2FlashDialog.html">UF2FlashDialog</a></td>
 <td>Module implementing a dialog to flash any UF2 capable device.</td>
 </tr>
--- a/src/eric7/MicroPython/CircuitPythonDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,533 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for CircuitPython boards.
-"""
-
-import os
-import shutil
-
-from PyQt6.QtCore import QProcess, QUrl, pyqtSlot
-from PyQt6.QtNetwork import QNetworkRequest
-from PyQt6.QtWidgets import QMenu
-
-from eric7 import Globals, Preferences
-from eric7.EricWidgets import EricFileDialog, EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-from eric7.SystemUtilities import FileSystemUtilities
-
-from .CircuitPythonUpdater.CircuitPythonUpdaterInterface import (
-    CircuitPythonUpdaterInterface,
-    isCircupAvailable,
-)
-from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class CircuitPythonDevice(MicroPythonDevice):
-    """
-    Class implementing the device for CircuitPython boards.
-    """
-
-    DeviceVolumeName = "CIRCUITPY"
-
-    def __init__(self, microPythonWidget, deviceType, boardName, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param boardName name of the board
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__boardName = boardName
-        self.__workspace = self.__findWorkspace()
-
-        self.__updater = CircuitPythonUpdaterInterface(self)
-
-        self.__createCPyMenu()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-        if self.__deviceVolumeMounted():
-            self.microPython.setActionButtons(open=True, save=True)
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return False
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.tr("CircuitPython")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def supportsLocalFileAccess(self):
-        """
-        Public method to indicate file access via a local directory.
-
-        @return flag indicating file access via local directory
-        @rtype bool
-        """
-        return self.__deviceVolumeMounted()
-
-    def __deviceVolumeMounted(self):
-        """
-        Private method to check, if the device volume is mounted.
-
-        @return flag indicated a mounted device
-        @rtype bool
-        """
-        if self.__workspace and not os.path.exists(self.__workspace):
-            self.__workspace = ""  # reset
-
-        return self.DeviceVolumeName in self.getWorkspace(silent=True)
-
-    def __findDeviceDirectories(self, directories):
-        """
-        Private method to find the device directories associated with the
-        current board name.
-
-        @param directories list of directories to be checked
-        @type list of str
-        @return list of associated directories
-        @rtype list of str
-        """
-        boardDirectories = []
-        for directory in directories:
-            bootFile = os.path.join(directory, "boot_out.txt")
-            if os.path.exists(bootFile):
-                with open(bootFile, "r") as f:
-                    line = f.readline()
-                if self.__boardName in line:
-                    boardDirectories.append(directory)
-
-        return boardDirectories
-
-    def __findWorkspace(self, silent=False):
-        """
-        Private method to find the workspace directory.
-
-        @param silent flag indicating silent operations
-        @type bool
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        # Attempts to find the paths on the filesystem that represents the
-        # plugged in CIRCUITPY boards.
-        deviceDirectories = FileSystemUtilities.findVolume(
-            self.DeviceVolumeName, findAll=True
-        )
-
-        if deviceDirectories:
-            if len(deviceDirectories) == 1:
-                return deviceDirectories[0]
-            else:
-                boardDirectories = self.__findDeviceDirectories(deviceDirectories)
-                if len(boardDirectories) == 1:
-                    return boardDirectories[0]
-                elif len(boardDirectories) > 1:
-                    return self.selectDeviceDirectory(boardDirectories)
-                else:
-                    return self.selectDeviceDirectory(deviceDirectories)
-        else:
-            # return the default workspace and give the user a warning (unless
-            # silent mode is selected)
-            if not silent:
-                EricMessageBox.warning(
-                    self.microPython,
-                    self.tr("Workspace Directory"),
-                    self.tr(
-                        "Python files for CircuitPython can be edited in"
-                        " place, if the device volume is locally"
-                        " available. Such a volume was not found. In"
-                        " place editing will not be available."
-                    ),
-                )
-
-            return super().getWorkspace()
-
-    def getWorkspace(self, silent=False):
-        """
-        Public method to get the workspace directory.
-
-        @param silent flag indicating silent operations
-        @type bool
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        if self.__workspace:
-            # return cached entry
-            return self.__workspace
-        else:
-            self.__workspace = self.__findWorkspace(silent=silent)
-            return self.__workspace
-
-    def __createCPyMenu(self):
-        """
-        Private method to create the CircuitPython submenu.
-        """
-        self.__libraryMenu = QMenu(self.tr("Library Management"))
-        self.__libraryMenu.aboutToShow.connect(self.__aboutToShowLibraryMenu)
-        self.__libraryMenu.setTearOffEnabled(True)
-
-        self.__cpyMenu = QMenu(self.tr("CircuitPython Functions"))
-
-        self.__cpyMenu.addAction(
-            self.tr("Show CircuitPython Versions"), self.__showCircuitPythonVersions
-        )
-        self.__cpyMenu.addSeparator()
-
-        lBoardName = self.microPython.getCurrentBoard().lower()
-        if "teensy" in lBoardName:
-            # Teensy 4.0 and 4.1 don't support UF2 flashing
-            self.__cpyMenu.addAction(
-                self.tr("CircuitPython Flash Instructions"),
-                self.__showTeensyFlashInstructions,
-            )
-            self.__flashCpyAct = self.__cpyMenu.addAction(
-                self.tr("Flash CircuitPython Firmware"), self.__startTeensyLoader
-            )
-            self.__flashCpyAct.setToolTip(
-                self.tr(
-                    "Start the 'Teensy Loader' application to flash the Teensy device."
-                )
-            )
-        else:
-            self.__flashCpyAct = self.__cpyMenu.addAction(
-                self.tr("Flash CircuitPython Firmware"), self.__flashCircuitPython
-            )
-        self.__cpyMenu.addSeparator()
-        self.__cpyMenu.addMenu(self.__libraryMenu)
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        linkConnected = self.microPython.isLinkConnected()
-
-        self.__flashCpyAct.setEnabled(not linkConnected)
-
-        menu.addMenu(self.__cpyMenu)
-
-    @pyqtSlot()
-    def __aboutToShowLibraryMenu(self):
-        """
-        Private slot to populate the 'Library Management' menu.
-        """
-        self.__libraryMenu.clear()
-
-        if isCircupAvailable():
-            self.__updater.populateMenu(self.__libraryMenu)
-        else:
-            act = self.__libraryMenu.addAction(
-                self.tr("Install Library Files"), self.__installLibraryFiles
-            )
-            act.setEnabled(self.__deviceVolumeMounted())
-            act = self.__libraryMenu.addAction(
-                self.tr("Install Library Package"),
-                lambda: self.__installLibraryFiles(packageMode=True),
-            )
-            act.setEnabled(self.__deviceVolumeMounted())
-            self.__libraryMenu.addSeparator()
-            self.__libraryMenu.addAction(
-                self.tr("Install 'circup' Package"),
-                self.__updater.installCircup,
-            )
-
-    def hasFlashMenuEntry(self):
-        """
-        Public method to check, if the device has its own flash menu entry.
-
-        @return flag indicating a specific flash menu entry
-        @rtype bool
-        """
-        return True
-
-    @pyqtSlot()
-    def __flashCircuitPython(self):
-        """
-        Private slot to flash a CircuitPython firmware to a device supporting UF2.
-        """
-        from .UF2FlashDialog import UF2FlashDialog
-
-        dlg = UF2FlashDialog(boardType="circuitpython")
-        dlg.exec()
-
-    def __showTeensyFlashInstructions(self):
-        """
-        Private method to show a message box because Teensy does not support
-        the UF2 bootloader yet.
-        """
-        EricMessageBox.information(
-            self.microPython,
-            self.tr("Flash CircuitPython Firmware"),
-            self.tr(
-                """<p>Teensy 4.0 and Teensy 4.1 do not support the UF2"""
-                """ bootloader. Please use the 'Teensy Loader'"""
-                """ application to flash CircuitPython. Make sure you"""
-                """ downloaded the CircuitPython .hex file.</p>"""
-                """<p>See <a href="{0}">the PJRC Teensy web site</a>"""
-                """ for details.</p>"""
-            ).format("https://www.pjrc.com/teensy/loader.html"),
-        )
-
-    def __startTeensyLoader(self):
-        """
-        Private method to start the 'Teensy Loader' application.
-
-        Note: The application must be accessible via the application search path.
-        """
-        ok, _ = QProcess.startDetached("teensy")
-        if not ok:
-            EricMessageBox.warning(
-                self.microPython,
-                self.tr("Start 'Teensy Loader'"),
-                self.tr(
-                    """<p>The 'Teensy Loader' application <b>teensy</b> could not"""
-                    """ be started. Ensure it is in the application search path or"""
-                    """ start it manually.</p>"""
-                ),
-            )
-
-    @pyqtSlot()
-    def __showCircuitPythonVersions(self):
-        """
-        Private slot to show the CircuitPython version of a connected device and
-        the latest available one (from Github).
-        """
-        ui = ericApp().getObject("UserInterface")
-        request = QNetworkRequest(QUrl(FirmwareGithubUrls["circuitpython"]))
-        reply = ui.networkAccessManager().head(request)
-        reply.finished.connect(lambda: self.__cpyVersionResponse(reply))
-
-    def __cpyVersionResponse(self, reply):
-        """
-        Private method handling the response of the latest version request.
-
-        @param reply reference to the reply object
-        @type QNetworkReply
-        """
-        latestUrl = reply.url().toString()
-        tag = latestUrl.rsplit("/", 1)[-1]
-        latestVersion = Globals.versionToTuple(tag)
-
-        cpyVersionStr = self.tr("unknown")
-        cpyVersion = (0, 0, 0)
-        if self.supportsLocalFileAccess():
-            bootFile = os.path.join(self.getWorkspace(), "boot_out.txt")
-            if os.path.exists(bootFile):
-                with open(bootFile, "r") as f:
-                    line = f.readline()
-                cpyVersionStr = line.split(";")[0].split()[2]
-                cpyVersion = Globals.versionToTuple(cpyVersionStr)
-        if (
-            cpyVersion == (0, 0, 0)
-            and self._deviceData
-            and self._deviceData["mpy_version"] != "unknown"
-        ):
-            # drive is not mounted or 'boot_out.txt' is missing but the device
-            # is connected via the serial console
-            cpyVersionStr = self._deviceData["mpy_version"]
-            cpyVersion = Globals.versionToTuple(cpyVersionStr)
-
-        msg = self.tr(
-            "<h4>CircuitPython Version Information</h4>"
-            "<table>"
-            "<tr><td>Installed:</td><td>{0}</td></tr>"
-            "<tr><td>Available:</td><td>{1}</td></tr>"
-            "</table>"
-        ).format(cpyVersionStr, tag)
-        if cpyVersion < latestVersion and cpyVersion != (0, 0, 0):
-            msg += self.tr("<p><b>Update available!</b></p>")
-
-        EricMessageBox.information(
-            None,
-            self.tr("CircuitPython Version"),
-            msg,
-        )
-
-    @pyqtSlot()
-    def __installLibraryFiles(self, packageMode=False):
-        """
-        Private slot to install Python files into the onboard library.
-
-        @param packageMode flag indicating to install a library package
-            (defaults to False)
-        @type bool (optional)
-        """
-        title = (
-            self.tr("Install Library Package")
-            if packageMode
-            else self.tr("Install Library Files")
-        )
-        if not self.__deviceVolumeMounted():
-            EricMessageBox.critical(
-                self.microPython,
-                title,
-                self.tr(
-                    """The device volume "<b>{0}</b>" is not available."""
-                    """ Ensure it is mounted properly and try again."""
-                ),
-            )
-            return
-
-        target = os.path.join(self.getWorkspace(), "lib")
-        # ensure that the library directory exists on the device
-        if not os.path.isdir(target):
-            os.makedirs(target)
-
-        if packageMode:
-            libraryPackage = EricFileDialog.getExistingDirectory(
-                self.microPython,
-                title,
-                os.path.expanduser("~"),
-                EricFileDialog.Option(0),
-            )
-            if libraryPackage:
-                target = os.path.join(target, os.path.basename(libraryPackage))
-                shutil.rmtree(target, ignore_errors=True)
-                shutil.copytree(libraryPackage, target)
-        else:
-            libraryFiles = EricFileDialog.getOpenFileNames(
-                self.microPython,
-                title,
-                os.path.expanduser("~"),
-                self.tr(
-                    "Compiled Python Files (*.mpy);;"
-                    "Python Files (*.py);;"
-                    "All Files (*)"
-                ),
-            )
-
-            for libraryFile in libraryFiles:
-                if os.path.exists(libraryFile):
-                    shutil.copy2(libraryFile, target)
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("CircuitPythonDocuUrl")
-
-    def getDownloadMenuEntries(self):
-        """
-        Public method to retrieve the entries for the downloads menu.
-
-        @return list of tuples with menu text and URL to be opened for each
-            entry
-        @rtype list of tuple of (str, str)
-        """
-        return [
-            (
-                self.tr("CircuitPython Firmware"),
-                Preferences.getMicroPython("CircuitPythonFirmwareUrl"),
-            ),
-            (
-                self.tr("CircuitPython Libraries"),
-                Preferences.getMicroPython("CircuitPythonLibrariesUrl"),
-            ),
-        ]
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype CircuitPythonDevice
-    """
-    return CircuitPythonDevice(microPythonWidget, deviceType, boardName)
--- a/src/eric7/MicroPython/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,668 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing an interface to the 'circup' package.
-"""
-
-import importlib
-import logging
-import os
-import re
-import shutil
-
-import requests
-
-from PyQt6.QtCore import QObject, pyqtSlot
-from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit, QMenu
-
-from eric7 import Preferences
-from eric7.EricGui.EricOverrideCursor import EricOverrideCursor
-from eric7.EricWidgets import EricFileDialog, EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog
-from eric7.SystemUtilities import PythonUtilities
-
-try:
-    import circup
-
-    circup.logger.setLevel(logging.WARNING)
-except ImportError:
-    circup = None
-
-
-class CircuitPythonUpdaterInterface(QObject):
-    """
-    Class implementing an interface to the 'circup' package.
-    """
-
-    def __init__(self, device, parent=None):
-        """
-        Constructor
-
-        @param device reference to the CircuitPython device interface
-        @type CircuitPythonDevice
-        @param parent reference to the parent object (defaults to None)
-        @type QObject (optional)
-        """
-        super().__init__(parent)
-
-        self.__device = device
-
-        self.__installMenu = QMenu(self.tr("Install Modules"))
-        self.__installMenu.setTearOffEnabled(True)
-        self.__installMenu.addAction(
-            self.tr("Select from Available Modules"), self.__installFromAvailable
-        )
-        self.__installMenu.addAction(
-            self.tr("Install Requirements"), self.__installRequirements
-        )
-        self.__installMenu.addAction(
-            self.tr("Install based on 'code.py'"), self.__installFromCode
-        )
-        self.__installMenu.addSeparator()
-        self.__installPyAct = self.__installMenu.addAction(
-            self.tr("Install Python Source")
-        )
-        self.__installPyAct.setCheckable(True)
-        self.__installPyAct.setChecked(False)
-        # kind of hack to make this action not hide the menu
-        # Note: parent menus are hidden nevertheless
-        self.__installPyAct.toggled.connect(self.__installMenu.show)
-
-    def populateMenu(self, menu):
-        """
-        Public method to populate the 'circup' menu.
-
-        @param menu reference to the menu to be populated
-        @type QMenu
-        """
-        from .CircupFunctions import patch_circup
-
-        patch_circup()
-        isMounted = self.__device.supportsLocalFileAccess()
-
-        act = menu.addAction(self.tr("circup"), self.__aboutCircup)
-        font = act.font()
-        font.setBold(True)
-        act.setFont(font)
-        menu.addSeparator()
-        menu.addAction(
-            self.tr("List Outdated Modules"), self.__listOutdatedModules
-        ).setEnabled(isMounted)
-        menu.addAction(self.tr("Update Modules"), self.__updateModules).setEnabled(
-            isMounted
-        )
-        menu.addAction(
-            self.tr("Update All Modules"), self.__updateAllModules
-        ).setEnabled(isMounted)
-        menu.addSeparator()
-        menu.addAction(self.tr("Show Available Modules"), self.__showAvailableModules)
-        menu.addAction(
-            self.tr("Show Installed Modules"), self.__showInstalledModules
-        ).setEnabled(isMounted)
-        menu.addMenu(self.__installMenu).setEnabled(isMounted)
-        menu.addAction(
-            self.tr("Uninstall Modules"), self.__uninstallModules
-        ).setEnabled(isMounted)
-        menu.addSeparator()
-        menu.addAction(
-            self.tr("Generate Requirements ..."), self.__generateRequirements
-        ).setEnabled(isMounted)
-        menu.addSeparator()
-        menu.addAction(self.tr("Show Bundles"), self.__showBundles)
-        menu.addAction(self.tr("Show Bundles with Modules"), self.__showBundlesModules)
-        menu.addSeparator()
-        menu.addAction(self.tr("Add Bundle"), self.__addBundle)
-        menu.addAction(self.tr("Remove Bundles"), self.__removeBundle)
-
-    @pyqtSlot()
-    def __aboutCircup(self):
-        """
-        Private slot to show some info about 'circup'.
-        """
-        version = circup.get_circup_version()
-        if version is None:
-            version = self.tr("unknown")
-
-        EricMessageBox.information(
-            None,
-            self.tr("About circup"),
-            self.tr(
-                """<p><b>circup Version {0}</b></p>"""
-                """<p><i>circup</i> is a tool to manage and update libraries on a"""
-                """ CircuitPython device.</p>""",
-            ).format(version),
-        )
-
-    @pyqtSlot()
-    def installCircup(self):
-        """
-        Public slot to install the 'circup' package via pip.
-        """
-        global circup
-
-        pip = ericApp().getObject("Pip")
-        pip.installPackages(
-            ["circup"], interpreter=PythonUtilities.getPythonExecutable()
-        )
-
-        circup = importlib.import_module("circup")
-        circup.logger.setLevel(logging.WARNING)
-
-    @pyqtSlot()
-    def __showBundles(self, withModules=False):
-        """
-        Private slot to show the available bundles (default and local).
-
-        @param withModules flag indicating to list the modules and their version
-            (defaults to False)
-        @type bool (optional)
-        """
-        from .ShowBundlesDialog import ShowBundlesDialog
-
-        with EricOverrideCursor():
-            dlg = ShowBundlesDialog(withModules=withModules)
-        dlg.exec()
-
-    @pyqtSlot()
-    def __showBundlesModules(self):
-        """
-        Private slot to show the available bundles (default and local) with their
-        modules.
-        """
-        self.__showBundles(withModules=True)
-
-    @pyqtSlot()
-    def __addBundle(self):
-        """
-        Private slot to add a bundle to the local bundles list, by "user/repo" github
-        string.
-        """
-        bundle, ok = QInputDialog.getText(
-            None,
-            self.tr("Add Bundle"),
-            self.tr("Enter Bundle by 'User/Repo' Github String:"),
-            QLineEdit.EchoMode.Normal,
-        )
-        if ok and bundle:
-            bundles = circup.get_bundles_local_dict()
-            modified = False
-
-            # do some cleanup
-            bundle = re.sub(r"https?://github.com/([^/]+/[^/]+)(/.*)?", r"\1", bundle)
-            if bundle in bundles:
-                EricMessageBox.information(
-                    None,
-                    self.tr("Add Bundle"),
-                    self.tr(
-                        """<p>The bundle <b>{0}</b> is already in the list.</p>"""
-                    ).format(bundle),
-                )
-                return
-
-            try:
-                cBundle = circup.Bundle(bundle)
-            except ValueError:
-                EricMessageBox.critical(
-                    None,
-                    self.tr("Add Bundle"),
-                    self.tr(
-                        """<p>The bundle string is invalid, expecting github URL"""
-                        """ or 'user/repository' string.</p>"""
-                    ),
-                )
-                return
-
-            result = requests.head("https://github.com/" + bundle)
-            if result.status_code == requests.codes.NOT_FOUND:
-                EricMessageBox.critical(
-                    None,
-                    self.tr("Add Bundle"),
-                    self.tr(
-                        """<p>The bundle string is invalid. The repository doesn't"""
-                        """ exist (error code 404).</p>"""
-                    ),
-                )
-                return
-
-            if not cBundle.validate():
-                EricMessageBox.critical(
-                    None,
-                    self.tr("Add Bundle"),
-                    self.tr(
-                        """<p>The bundle string is invalid. Is the repository a valid"""
-                        """ circup bundle?</p>"""
-                    ),
-                )
-                return
-
-            # Use the bundle string as the dictionary key for uniqueness
-            bundles[bundle] = bundle
-            modified = True
-            EricMessageBox.information(
-                None,
-                self.tr("Add Bundle"),
-                self.tr("""<p>Added bundle <b>{0}</b> ({1}).</p>""").format(
-                    bundle, cBundle.url
-                ),
-            )
-
-            if modified:
-                # save the bundles list
-                circup.save_local_bundles(bundles)
-                # update and get the new bundle for the first time
-                circup.get_bundle_versions(circup.get_bundles_list())
-
-    @pyqtSlot()
-    def __removeBundle(self):
-        """
-        Private slot to remove one or more bundles from the local bundles list.
-        """
-        localBundles = circup.get_bundles_local_dict()
-        dlg = EricListSelectionDialog(
-            sorted(localBundles.keys()),
-            title=self.tr("Remove Bundles"),
-            message=self.tr("Select the bundles to be removed:"),
-            checkBoxSelection=True,
-        )
-        modified = False
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            bundles = dlg.getSelection()
-            for bundle in bundles:
-                del localBundles[bundle]
-                modified = True
-
-        if modified:
-            circup.save_local_bundles(localBundles)
-            EricMessageBox.information(
-                None,
-                self.tr("Remove Bundles"),
-                self.tr(
-                    """<p>These bundles were removed from the local bundles list.{0}"""
-                    """</p>"""
-                ).format("""<ul><li>{0}</li></ul>""".format("</li><li>".join(bundles))),
-            )
-
-    @pyqtSlot()
-    def __listOutdatedModules(self):
-        """
-        Private slot to list the outdated modules of the connected device.
-        """
-        from .ShowOutdatedDialog import ShowOutdatedDialog
-
-        devicePath = self.__device.getWorkspace()
-
-        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
-        circup.CPY_VERSION = cpyVersion
-
-        with EricOverrideCursor():
-            dlg = ShowOutdatedDialog(devicePath=devicePath)
-        dlg.exec()
-
-    @pyqtSlot()
-    def __updateModules(self):
-        """
-        Private slot to update the modules of the connected device.
-        """
-        from .ShowOutdatedDialog import ShowOutdatedDialog
-
-        devicePath = self.__device.getWorkspace()
-
-        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
-        circup.CPY_VERSION = cpyVersion
-
-        with EricOverrideCursor():
-            dlg = ShowOutdatedDialog(devicePath=devicePath, selectionMode=True)
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            modules = dlg.getSelection()
-            self.__doUpdateModules(modules)
-
-    @pyqtSlot()
-    def __updateAllModules(self):
-        """
-        Private slot to update all modules of the connected device.
-        """
-        devicePath = self.__device.getWorkspace()
-
-        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
-        circup.CPY_VERSION = cpyVersion
-
-        with EricOverrideCursor():
-            modules = [
-                m
-                for m in circup.find_modules(devicePath, circup.get_bundles_list())
-                if m.outofdate
-            ]
-        if modules:
-            self.__doUpdateModules(modules)
-        else:
-            EricMessageBox.information(
-                None,
-                self.tr("Update Modules"),
-                self.tr("All modules are already up-to-date."),
-            )
-
-    def __doUpdateModules(self, modules):
-        """
-        Private method to perform the update of a list of modules.
-
-        @param modules list of modules to be updated
-        @type circup.Module
-        """
-        updatedModules = []
-        for module in modules:
-            try:
-                module.update()
-                updatedModules.append(module.name)
-            except Exception as ex:
-                EricMessageBox.critical(
-                    None,
-                    self.tr("Update Modules"),
-                    self.tr(
-                        """<p>There was an error updating <b>{0}</b>.</p>"""
-                        """<p>Error: {1}</p>"""
-                    ).format(module.name, str(ex)),
-                )
-
-        if updatedModules:
-            EricMessageBox.information(
-                None,
-                self.tr("Update Modules"),
-                self.tr(
-                    """<p>These modules were updated on the connected device.{0}</p>"""
-                ).format(
-                    """<ul><li>{0}</li></ul>""".format("</li><li>".join(updatedModules))
-                ),
-            )
-        else:
-            EricMessageBox.information(
-                None,
-                self.tr("Update Modules"),
-                self.tr("No modules could be updated."),
-            )
-
-    @pyqtSlot()
-    def __showAvailableModules(self):
-        """
-        Private slot to show the available modules.
-
-        These are modules which could be installed on the device.
-        """
-        from ..ShowModulesDialog import ShowModulesDialog
-
-        with EricOverrideCursor():
-            availableModules = circup.get_bundle_versions(circup.get_bundles_list())
-            moduleNames = [m.replace(".py", "") for m in availableModules]
-
-        dlg = ShowModulesDialog(moduleNames)
-        dlg.exec()
-
-    @pyqtSlot()
-    def __showInstalledModules(self):
-        """
-        Private slot to show the modules installed on the connected device.
-        """
-        from .ShowInstalledDialog import ShowInstalledDialog
-
-        devicePath = self.__device.getWorkspace()
-
-        with EricOverrideCursor():
-            dlg = ShowInstalledDialog(devicePath=devicePath)
-        dlg.exec()
-
-    @pyqtSlot()
-    def __installFromAvailable(self):
-        """
-        Private slot to install modules onto the connected device.
-        """
-        from ..ShowModulesDialog import ShowModulesDialog
-
-        with EricOverrideCursor():
-            availableModules = circup.get_bundle_versions(circup.get_bundles_list())
-            moduleNames = [m.replace(".py", "") for m in availableModules]
-
-        dlg = ShowModulesDialog(moduleNames, selectionMode=True)
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            modules = dlg.getSelection()
-            self.__installModules(modules)
-
-    @pyqtSlot()
-    def __installRequirements(self):
-        """
-        Private slot to install modules determined by a requirements file.
-        """
-        homeDir = (
-            Preferences.getMicroPython("MpyWorkspace")
-            or Preferences.getMultiProject("Workspace")
-            or os.path.expanduser("~")
-        )
-        reqFile = EricFileDialog.getOpenFileName(
-            None,
-            self.tr("Install Modules"),
-            homeDir,
-            self.tr("Text Files (*.txt);;All Files (*)"),
-        )
-        if reqFile:
-            if os.path.exists(reqFile):
-                with open(reqFile, "r") as fp:
-                    requirementsText = fp.read()
-                modules = circup.libraries_from_requirements(requirementsText)
-                if modules:
-                    self.__installModules(modules)
-                else:
-                    EricMessageBox.critical(
-                        None,
-                        self.tr("Install Modules"),
-                        self.tr(
-                            """<p>The given requirements file <b>{0}</b> does not"""
-                            """ contain valid modules.</p>"""
-                        ).format(reqFile),
-                    )
-            else:
-                EricMessageBox.critical(
-                    None,
-                    self.tr("Install Modules"),
-                    self.tr(
-                        """<p>The given requirements file <b>{0}</b> does not exist."""
-                        """</p>"""
-                    ).format(reqFile),
-                )
-
-    @pyqtSlot()
-    def __installFromCode(self):
-        """
-        Private slot to install modules based on the 'code.py' file of the
-        connected device.
-        """
-        devicePath = self.__device.getWorkspace()
-
-        codeFile = EricFileDialog.getOpenFileName(
-            None,
-            self.tr("Install Modules"),
-            os.path.join(devicePath, "code.py"),
-            self.tr("Python Files (*.py);;All Files (*)"),
-        )
-        if codeFile:
-            if os.path.exists(codeFile):
-                with EricOverrideCursor():
-                    availableModules = circup.get_bundle_versions(
-                        circup.get_bundles_list()
-                    )
-                    moduleNames = {}
-                    for module, metadata in availableModules.items():
-                        moduleNames[module.replace(".py", "")] = metadata
-
-                modules = circup.libraries_from_imports(codeFile, moduleNames)
-                if modules:
-                    self.__installModules(modules)
-                else:
-                    EricMessageBox.critical(
-                        None,
-                        self.tr("Install Modules"),
-                        self.tr(
-                            """<p>The given code file <b>{0}</b> does not"""
-                            """ contain valid import statements or does not import"""
-                            """ external modules.</p>"""
-                        ).format(codeFile),
-                    )
-            else:
-                EricMessageBox.critical(
-                    None,
-                    self.tr("Install Modules"),
-                    self.tr(
-                        """<p>The given code file <b>{0}</b> does not exist.</p>"""
-                    ).format(codeFile),
-                )
-
-    def __installModules(self, installs):
-        """
-        Private method to install the given list of modules.
-
-        @param installs list of module names to be installed
-        @type list of str
-        """
-        devicePath = self.__device.getWorkspace()
-
-        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
-        circup.CPY_VERSION = cpyVersion
-
-        with EricOverrideCursor():
-            availableModules = circup.get_bundle_versions(circup.get_bundles_list())
-            moduleNames = {}
-            for module, metadata in availableModules.items():
-                moduleNames[module.replace(".py", "")] = metadata
-            toBeInstalled = circup.get_dependencies(installs, mod_names=moduleNames)
-            deviceModules = circup.get_device_versions(devicePath)
-        if toBeInstalled is not None:
-            dependencies = [m for m in toBeInstalled if m not in installs]
-            ok = EricMessageBox.yesNo(
-                None,
-                self.tr("Install Modules"),
-                self.tr("""<p>Ready to install these modules?{0}{1}</p>""").format(
-                    """<ul><li>{0}</li></ul>""".format(
-                        "</li><li>".join(sorted(installs))
-                    ),
-                    self.tr("Dependencies:")
-                    + """<ul><li>{0}</li></ul>""".format(
-                        "</li><li>".join(sorted(dependencies))
-                    )
-                    if dependencies
-                    else "",
-                ),
-                yesDefault=True,
-            )
-            if ok:
-                installedModules = []
-                with EricOverrideCursor():
-                    for library in toBeInstalled:
-                        success = circup.install_module(
-                            devicePath,
-                            deviceModules,
-                            library,
-                            self.__installPyAct.isChecked(),
-                            moduleNames,
-                        )
-                        if success:
-                            installedModules.append(library)
-
-                if installedModules:
-                    EricMessageBox.information(
-                        None,
-                        self.tr("Install Modules"),
-                        self.tr(
-                            "<p>Installation complete. These modules were installed"
-                            " successfully.{0}</p>"
-                        ).format(
-                            """<ul><li>{0}</li></ul>""".format(
-                                "</li><li>".join(sorted(installedModules))
-                            ),
-                        ),
-                    )
-                else:
-                    EricMessageBox.information(
-                        None,
-                        self.tr("Install Modules"),
-                        self.tr(
-                            "<p>Installation complete. No modules were installed.</p>"
-                        ),
-                    )
-        else:
-            EricMessageBox.information(
-                None,
-                self.tr("Install Modules"),
-                self.tr("<p>No modules installation is required.</p>"),
-            )
-
-    @pyqtSlot()
-    def __uninstallModules(self):
-        """
-        Private slot to uninstall modules from the connected device.
-        """
-        devicePath = self.__device.getWorkspace()
-        libraryPath = os.path.join(devicePath, "lib")
-
-        with EricOverrideCursor():
-            deviceModules = circup.get_device_versions(devicePath)
-        modNames = {}
-        for moduleItem, metadata in deviceModules.items():
-            modNames[moduleItem.replace(".py", "").lower()] = metadata
-
-        dlg = EricListSelectionDialog(
-            sorted(modNames.keys()),
-            title=self.tr("Uninstall Modules"),
-            message=self.tr("Select the modules/packages to be uninstalled:"),
-            checkBoxSelection=True,
-        )
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            names = dlg.getSelection()
-            for name in names:
-                modulePath = modNames[name]["path"]
-                if os.path.isdir(modulePath):
-                    target = os.path.basename(os.path.dirname(modulePath))
-                    targetPath = os.path.join(libraryPath, target)
-                    # Remove the package directory.
-                    shutil.rmtree(targetPath)
-                else:
-                    target = os.path.basename(modulePath)
-                    targetPath = os.path.join(libraryPath, target)
-                    # Remove the module file
-                    os.remove(targetPath)
-
-            EricMessageBox.information(
-                None,
-                self.tr("Uninstall Modules"),
-                self.tr(
-                    """<p>These modules/packages were uninstalled from the connected"""
-                    """ device.{0}</p>"""
-                ).format("""<ul><li>{0}</li></ul>""".format("</li><li>".join(names))),
-            )
-
-    @pyqtSlot()
-    def __generateRequirements(self):
-        """
-        Private slot to generate requirements for the connected device.
-        """
-        from .RequirementsDialog import RequirementsDialog
-
-        devicePath = self.__device.getWorkspace()
-
-        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
-        circup.CPY_VERSION = cpyVersion
-
-        dlg = RequirementsDialog(devicePath=devicePath)
-        dlg.exec()
-
-
-def isCircupAvailable():
-    """
-    Function to check for the availability of 'circup'.
-
-    @return flag indicating the availability of 'circup'
-    @rtype bool
-    """
-    global circup
-
-    return circup is not None
--- a/src/eric7/MicroPython/CircuitPythonUpdater/CircupFunctions.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,254 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing variants of some 'circup' functions suitable for 'eric-ide'
-integration.
-"""
-
-#
-# Copyright of the original sources:
-# Copyright (c) 2019 Adafruit Industries
-#
-
-import os
-import shutil
-
-import circup
-import requests
-
-from PyQt6.QtCore import QCoreApplication
-
-from eric7.EricWidgets import EricMessageBox
-
-
-def find_modules(device_path, bundles_list):
-    """
-    Function to extract metadata from the connected device and available bundles and
-    returns this as a list of Module instances representing the modules on the device.
-
-    @param device_path path to the connected board
-    @type str
-    @param bundles_list list of supported bundles
-    @type list of circup.Bundle
-    @return list of Module instances describing the current state of the
-        modules on the connected device
-    @rtype list of circup.Module
-    """
-    result = []
-    try:
-        device_modules = circup.get_device_versions(device_path)
-        bundle_modules = circup.get_bundle_versions(bundles_list)
-        for name, device_metadata in device_modules.items():
-            if name in bundle_modules:
-                path = device_metadata["path"]
-                bundle_metadata = bundle_modules[name]
-                repo = bundle_metadata.get("__repo__")
-                bundle = bundle_metadata.get("bundle")
-                device_version = device_metadata.get("__version__")
-                bundle_version = bundle_metadata.get("__version__")
-                mpy = device_metadata["mpy"]
-                compatibility = device_metadata.get("compatibility", (None, None))
-                result.append(
-                    circup.Module(
-                        path,
-                        repo,
-                        device_version,
-                        bundle_version,
-                        mpy,
-                        bundle,
-                        compatibility,
-                    )
-                )
-    except Exception as ex:
-        # If it's not possible to get the device and bundle metadata, bail out
-        # with a friendly message and indication of what's gone wrong.
-        EricMessageBox.critical(
-            None,
-            QCoreApplication.translate("CircupFunctions", "Find Modules"),
-            QCoreApplication.translate(
-                "CircupFunctions", """<p>There was an error: {0}</p>"""
-            ).format(str(ex)),
-        )
-
-    return result
-
-
-def ensure_latest_bundle(bundle):
-    """
-    Function to ensure that there's a copy of the latest library bundle available so
-    circup can check the metadata contained therein.
-
-    @param bundle reference to the target Bundle object.
-    @type circup.Bundle
-    """
-    tag = bundle.latest_tag
-    do_update = False
-    if tag == bundle.current_tag:
-        for platform in circup.PLATFORMS:
-            # missing directories (new platform added on an existing install
-            # or side effect of pytest or network errors)
-            do_update = do_update or not os.path.isdir(bundle.lib_dir(platform))
-    else:
-        do_update = True
-
-    if do_update:
-        try:
-            circup.get_bundle(bundle, tag)
-            circup.tags_data_save_tag(bundle.key, tag)
-        except requests.exceptions.HTTPError as ex:
-            EricMessageBox.critical(
-                None,
-                QCoreApplication.translate("CircupFunctions", "Download Bundle"),
-                QCoreApplication.translate(
-                    "CircupFunctions",
-                    """<p>There was a problem downloading the bundle. Please try"""
-                    """ again in a moment.</p><p>Error: {0}</p>""",
-                ).format(str(ex)),
-            )
-
-
-def get_circuitpython_version(device_path):
-    """
-    Function to return the version number of CircuitPython running on the board
-    connected via ``device_path``, along with the board ID.
-
-    This is obtained from the 'boot_out.txt' file on the device, whose first line
-    will start with something like this:
-
-        Adafruit CircuitPython 4.1.0 on 2019-08-02;
-
-    While the second line is:
-
-        Board ID:raspberry_pi_pico
-
-    @param device_path path to the connected board.
-    @type str
-    @return tuple with the version string for CircuitPython and the board ID string
-    @rtype tuple of (str, str)
-    """
-    try:
-        with open(os.path.join(device_path, "boot_out.txt")) as boot:
-            version_line = boot.readline()
-            circuit_python = version_line.split(";")[0].split(" ")[-3]
-            board_line = boot.readline()
-            board_id = (
-                board_line[9:].strip() if board_line.startswith("Board ID:") else ""
-            )
-    except FileNotFoundError:
-        EricMessageBox.critical(
-            None,
-            QCoreApplication.translate("CircupFunctions", "Download Bundle"),
-            QCoreApplication.translate(
-                "CircupFunctions",
-                """<p>Missing file <b>boot_out.txt</b> on the device: wrong path or"""
-                """ drive corrupted.</p>""",
-            ),
-        )
-        circuit_python, board_id = "", ""
-
-    return (circuit_python, board_id)
-
-
-def install_module(device_path, device_modules, name, py, mod_names):
-    """
-    Function to find a connected device and install a given module name.
-
-    Installation is done if it is available in the current module bundle and is not
-    already installed on the device.
-
-    @param device_path path to the connected board
-    @type str
-    @param device_modules list of module metadata from the device
-    @type list of dict
-    @param name name of the module to be installed
-    @type str
-    @param py flag indicating if the module should be installed from source or
-        from a pre-compiled module
-    @type bool
-    @param mod_names dictionary containing metadata from modules that can be generated
-        with circup.get_bundle_versions()
-    @type dict
-    @return flag indicating success
-    @rtype bool
-    """
-    if not name:
-        return False
-    elif name in mod_names:
-        library_path = os.path.join(device_path, "lib")
-        if not os.path.exists(library_path):  # pragma: no cover
-            os.makedirs(library_path)
-        metadata = mod_names[name]
-        bundle = metadata["bundle"]
-        # Grab device modules to check if module already installed
-        if name in device_modules:
-            # ignore silently
-            return False
-        if py:
-            # Use Python source for module.
-            source_path = metadata["path"]  # Path to Python source version.
-            if os.path.isdir(source_path):
-                target = os.path.basename(os.path.dirname(source_path))
-                target_path = os.path.join(library_path, target)
-                # Copy the directory.
-                shutil.copytree(source_path, target_path)
-                return True
-            else:
-                target = os.path.basename(source_path)
-                target_path = os.path.join(library_path, target)
-                # Copy file.
-                shutil.copyfile(source_path, target_path)
-                return True
-        else:
-            # Use pre-compiled mpy modules.
-            module_name = os.path.basename(metadata["path"]).replace(".py", ".mpy")
-            if not module_name:
-                # Must be a directory based module.
-                module_name = os.path.basename(os.path.dirname(metadata["path"]))
-            major_version = circup.CPY_VERSION.split(".")[0]
-            bundle_platform = "{0}mpy".format(major_version)
-            bundle_path = os.path.join(bundle.lib_dir(bundle_platform), module_name)
-            if os.path.isdir(bundle_path):
-                target_path = os.path.join(library_path, module_name)
-                # Copy the directory.
-                shutil.copytree(bundle_path, target_path)
-                return True
-            elif os.path.isfile(bundle_path):
-                target = os.path.basename(bundle_path)
-                target_path = os.path.join(library_path, target)
-                # Copy file.
-                shutil.copyfile(bundle_path, target_path)
-                return True
-            else:
-                EricMessageBox.critical(
-                    None,
-                    QCoreApplication.translate("CircupFunctions", "Install Modules"),
-                    QCoreApplication.translate(
-                        "CircupFunctions",
-                        """<p>The compiled version of module <b>{0}</b> cannot be"""
-                        """ found.</p>""",
-                    ).format(name),
-                )
-                return False
-    else:
-        EricMessageBox.critical(
-            None,
-            QCoreApplication.translate("CircupFunctions", "Install Modules"),
-            QCoreApplication.translate(
-                "CircupFunctions", """<p>The module name <b>{0}</b> is not known.</p>"""
-            ).format(name),
-        )
-        return False
-
-
-def patch_circup():
-    """
-    Function to patch 'circup' to use our functions adapted to the use within the
-    eric-ide.
-    """
-    circup.ensure_latest_bundle = ensure_latest_bundle
-    circup.find_modules = find_modules
-    circup.get_circuitpython_version = get_circuitpython_version
-    circup.install_module = install_module
--- a/src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to generate a requirements file.
-"""
-
-import os
-
-import circup
-
-from PyQt6.QtCore import pyqtSlot
-from PyQt6.QtGui import QGuiApplication
-from PyQt6.QtWidgets import QAbstractButton, QDialog, QDialogButtonBox
-
-from eric7.EricWidgets import EricFileDialog, EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
-from eric7.SystemUtilities import FileSystemUtilities
-
-from .Ui_RequirementsDialog import Ui_RequirementsDialog
-
-
-class RequirementsDialog(QDialog, Ui_RequirementsDialog):
-    """
-    Class implementing a dialog to generate a requirements file.
-    """
-
-    def __init__(self, devicePath, parent=None):
-        """
-        Constructor
-
-        @param devicePath path to the connected board
-        @type str
-        @param parent reference to the parent widget (defaults to None)
-        @type QWidget (optional)
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-
-        self.__title = self.tr("Generate Requirements")
-
-        self.__refreshButton = self.buttonBox.addButton(
-            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole
-        )
-
-        self.requirementsFilePicker.setMode(EricPathPickerModes.SAVE_FILE_MODE)
-        self.requirementsFilePicker.setFilters(
-            self.tr("Text Files (*.txt);;All Files (*)")
-        )
-
-        self.__devicePath = devicePath
-
-        self.__requirementsEdited = False
-        self.__requirementsAvailable = False
-
-        self.__generateRequirements()
-
-    def __updateButtons(self):
-        """
-        Private method to set the state of the various buttons.
-        """
-        self.saveButton.setEnabled(
-            self.__requirementsAvailable
-            and bool(self.requirementsFilePicker.text())
-            and os.path.isabs(self.requirementsFilePicker.text())
-        )
-        self.saveToButton.setEnabled(self.__requirementsAvailable)
-        self.copyButton.setEnabled(self.__requirementsAvailable)
-
-        aw = ericApp().getObject("ViewManager").activeWindow()
-        if aw and self.__requirementsAvailable:
-            self.insertButton.setEnabled(True)
-            self.replaceAllButton.setEnabled(True)
-            self.replaceSelectionButton.setEnabled(aw.hasSelectedText())
-        else:
-            self.insertButton.setEnabled(False)
-            self.replaceAllButton.setEnabled(False)
-            self.replaceSelectionButton.setEnabled(False)
-
-    @pyqtSlot(str)
-    def on_requirementsFilePicker_textChanged(self, txt):
-        """
-        Private slot handling a change of the requirements file name.
-
-        @param txt name of the requirements file
-        @type str
-        """
-        self.__updateButtons()
-
-    @pyqtSlot()
-    def on_requirementsEdit_textChanged(self):
-        """
-        Private slot handling changes of the requirements text.
-        """
-        self.__requirementsEdited = True
-
-    @pyqtSlot(QAbstractButton)
-    def on_buttonBox_clicked(self, button):
-        """
-        Private slot called by a button of the button box clicked.
-
-        @param button button that was clicked
-        @type QAbstractButton
-        """
-        if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
-            self.close()
-        elif button == self.__refreshButton:
-            self.__generateRequirements()
-
-    def __generateRequirements(self):
-        """
-        Private slot to generate the requirements specifiers list.
-        """
-        ok = (
-            EricMessageBox.yesNo(
-                self,
-                self.__title,
-                self.tr(
-                    """The requirements were changed. Do you want"""
-                    """ to overwrite these changes?"""
-                ),
-            )
-            if self.__requirementsEdited
-            else True
-        )
-        if ok:
-            self.requirementsEdit.clear()
-            self.__requirementsAvailable = False
-
-            if not bool(self.requirementsFilePicker.text()):
-                self.requirementsFilePicker.setText("requirements.txt")
-
-            fileName = FileSystemUtilities.toNativeSeparators(
-                self.requirementsFilePicker.text()
-            )
-            if fileName and not os.path.isabs(fileName):
-                fileName = ""
-
-            modules = circup.find_modules(self.__devicePath, circup.get_bundles_list())
-            specifiers = []
-            if modules:
-                for module in modules:
-                    specifiers.append(
-                        "{0}=={1}".format(module.name, module.device_version)
-                    )
-
-            if specifiers:
-                self.requirementsEdit.setPlainText("\n".join(specifiers) + "\n")
-                self.__requirementsAvailable = True
-            else:
-                self.requirementsEdit.setPlainText(
-                    self.tr("No package specifiers generated.")
-                )
-
-            self.__updateButtons()
-
-            self.__requirementsEdited = False
-
-    def __writeToFile(self, fileName):
-        """
-        Private method to write the requirements text to a file.
-
-        @param fileName name of the file to write to
-        @type str
-        """
-        if os.path.exists(fileName):
-            ok = EricMessageBox.warning(
-                self,
-                self.__title,
-                self.tr(
-                    """The file <b>{0}</b> already exists. Do you want"""
-                    """ to overwrite it?"""
-                ).format(fileName),
-            )
-            if not ok:
-                return
-
-        txt = self.requirementsEdit.toPlainText()
-        try:
-            with open(fileName, "w") as f:
-                f.write(txt)
-        except OSError as err:
-            EricMessageBox.critical(
-                self,
-                self.__title,
-                self.tr(
-                    """<p>The requirements could not be written"""
-                    """ to <b>{0}</b>.</p><p>Reason: {1}</p>"""
-                ).format(fileName, str(err)),
-            )
-
-    @pyqtSlot()
-    def on_saveButton_clicked(self):
-        """
-        Private slot to save the requirements text to the requirements file.
-        """
-        fileName = self.requirementsFilePicker.text()
-        self.__writeToFile(fileName)
-
-    @pyqtSlot()
-    def on_saveToButton_clicked(self):
-        """
-        Private slot to write the requirements text to a new file.
-        """
-        fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
-            self,
-            self.__title,
-            os.path.expanduser("~"),
-            self.tr("Text Files (*.txt);;All Files (*)"),
-            None,
-            EricFileDialog.DontConfirmOverwrite,
-        )
-        if fileName:
-            ext = os.path.splitext(fileName)[1]
-            if not ext:
-                ex = selectedFilter.split("(*")[1].split(")")[0]
-                if ex:
-                    fileName += ex
-            self.__writeToFile(fileName)
-
-    @pyqtSlot()
-    def on_copyButton_clicked(self):
-        """
-        Private slot to copy the requirements text to the clipboard.
-        """
-        txt = self.requirementsEdit.toPlainText()
-        cb = QGuiApplication.clipboard()
-        cb.setText(txt)
-
-    @pyqtSlot()
-    def on_insertButton_clicked(self):
-        """
-        Private slot to insert the requirements text at the cursor position
-        of the current editor.
-        """
-        aw = ericApp().getObject("ViewManager").activeWindow()
-        if aw:
-            aw.beginUndoAction()
-            aw.insert(self.requirementsEdit.toPlainText())
-            aw.endUndoAction()
-
-    @pyqtSlot()
-    def on_replaceSelectionButton_clicked(self):
-        """
-        Private slot to replace the selected text of the current editor
-        with the requirements text.
-        """
-        aw = ericApp().getObject("ViewManager").activeWindow()
-        if aw:
-            aw.beginUndoAction()
-            aw.replaceSelectedText(self.requirementsEdit.toPlainText())
-            aw.endUndoAction()
-
-    @pyqtSlot()
-    def on_replaceAllButton_clicked(self):
-        """
-        Private slot to replace the text of the current editor with the
-        requirements text.
-        """
-        aw = ericApp().getObject("ViewManager").activeWindow()
-        if aw:
-            aw.setText(self.requirementsEdit.toPlainText())
--- a/src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.ui	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>RequirementsDialog</class>
- <widget class="QDialog" name="RequirementsDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>550</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Generate Requirements</string>
-  </property>
-  <property name="toolTip">
-   <string>Replace the current selection with the requirements text</string>
-  </property>
-  <property name="sizeGripEnabled">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QLabel" name="label">
-       <property name="text">
-        <string>Requirements File:</string>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="EricPathPicker" name="requirementsFilePicker" native="true">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::StrongFocus</enum>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="3" column="1">
-      <widget class="Line" name="line">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QPushButton" name="copyButton">
-       <property name="toolTip">
-        <string>Copy the requirements text to the clipboard</string>
-       </property>
-       <property name="text">
-        <string>Copy</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QPushButton" name="saveButton">
-       <property name="toolTip">
-        <string>Press to save to the requirements file</string>
-       </property>
-       <property name="text">
-        <string>Save</string>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="1">
-      <widget class="QPushButton" name="insertButton">
-       <property name="toolTip">
-        <string>Insert the requirements text at the cursor position</string>
-       </property>
-       <property name="text">
-        <string>Insert</string>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="1">
-      <widget class="QPushButton" name="replaceSelectionButton">
-       <property name="text">
-        <string>Replace Selection</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="0" rowspan="9">
-      <widget class="QPlainTextEdit" name="requirementsEdit">
-       <property name="tabChangesFocus">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="7" column="1">
-      <widget class="QPushButton" name="replaceAllButton">
-       <property name="toolTip">
-        <string>Replace all text with the requirements text</string>
-       </property>
-       <property name="text">
-        <string>Replace All</string>
-       </property>
-      </widget>
-     </item>
-     <item row="8" column="1">
-      <spacer name="verticalSpacer">
-       <property name="orientation">
-        <enum>Qt::Vertical</enum>
-       </property>
-       <property name="sizeHint" stdset="0">
-        <size>
-         <width>20</width>
-         <height>40</height>
-        </size>
-       </property>
-      </spacer>
-     </item>
-     <item row="1" column="1">
-      <widget class="QPushButton" name="saveToButton">
-       <property name="toolTip">
-        <string>Save to a new file</string>
-       </property>
-       <property name="text">
-        <string>Save To</string>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="1">
-      <widget class="QLabel" name="label_2">
-       <property name="text">
-        <string>&lt;b&gt;Editor Actions&lt;/b&gt;</string>
-       </property>
-       <property name="alignment">
-        <set>Qt::AlignCenter</set>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <customwidgets>
-  <customwidget>
-   <class>EricPathPicker</class>
-   <extends>QWidget</extends>
-   <header>eric7/EricWidgets/EricPathPicker.h</header>
-   <container>1</container>
-  </customwidget>
- </customwidgets>
- <tabstops>
-  <tabstop>requirementsFilePicker</tabstop>
-  <tabstop>requirementsEdit</tabstop>
-  <tabstop>saveButton</tabstop>
-  <tabstop>saveToButton</tabstop>
-  <tabstop>copyButton</tabstop>
-  <tabstop>insertButton</tabstop>
-  <tabstop>replaceSelectionButton</tabstop>
-  <tabstop>replaceAllButton</tabstop>
- </tabstops>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>RequirementsDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>RequirementsDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
--- a/src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog showing the available bundles and their modules.
-"""
-
-import circup
-
-from PyQt6.QtCore import Qt
-from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
-
-from .Ui_ShowBundlesDialog import Ui_ShowBundlesDialog
-
-
-class ShowBundlesDialog(QDialog, Ui_ShowBundlesDialog):
-    """
-    Class implementing a dialog showing the available bundles and their modules.
-    """
-
-    def __init__(self, withModules, parent=None):
-        """
-        Constructor
-
-        @param withModules flag indicating to list the modules and their version
-        @type bool
-        @param parent reference to the parent widget (defaults to None)
-        @type QWidget (optional)
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-
-        self.header.setText(
-            self.tr("Available Bundles and Modules")
-            if withModules
-            else self.tr("Available Bundles")
-        )
-        self.bundlesWidget.setColumnCount(2)
-
-        localBundles = circup.get_bundles_local_dict().values()
-        bundles = circup.get_bundles_list()
-        availableModules = circup.get_bundle_versions(bundles)
-
-        for bundle in bundles:
-            topItm = QTreeWidgetItem(
-                self.bundlesWidget, [bundle.key, bundle.current_tag]
-            )
-            topItm.setExpanded(True)
-            if bundle.key in localBundles:
-                font = topItm.font(0)
-                font.setUnderline(True)
-                topItm.setFont(0, font)
-            itm = QTreeWidgetItem(topItm, [bundle.url])
-            itm.setFirstColumnSpanned(True)
-
-            if withModules:
-                modulesHeader = QTreeWidgetItem(topItm, [self.tr("Modules")])
-                modulesHeader.setExpanded(True)
-                for name, mod in sorted(availableModules.items()):
-                    if mod["bundle"] == bundle:
-                        QTreeWidgetItem(
-                            modulesHeader,
-                            [name, mod.get("__version__", self.tr("unknown"))],
-                        )
-
-        self.bundlesWidget.resizeColumnToContents(0)
-        self.bundlesWidget.resizeColumnToContents(1)
-        self.bundlesWidget.sortItems(0, Qt.SortOrder.AscendingOrder)
--- a/src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.ui	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ShowBundlesDialog</class>
- <widget class="QDialog" name="ShowBundlesDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>700</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>CircuitPython Bundles</string>
-  </property>
-  <property name="sizeGripEnabled">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QLabel" name="header">
-     <property name="text">
-      <string/>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QTreeWidget" name="bundlesWidget">
-     <property name="alternatingRowColors">
-      <bool>true</bool>
-     </property>
-     <property name="selectionMode">
-      <enum>QAbstractItemView::NoSelection</enum>
-     </property>
-     <property name="rootIsDecorated">
-      <bool>false</bool>
-     </property>
-     <property name="headerHidden">
-      <bool>true</bool>
-     </property>
-     <property name="expandsOnDoubleClick">
-      <bool>false</bool>
-     </property>
-     <column>
-      <property name="text">
-       <string notr="true">1</string>
-      </property>
-     </column>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>ShowBundlesDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>ShowBundlesDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
--- a/src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to show the modules installed on the connected device.
-"""
-
-import circup
-
-from PyQt6.QtCore import Qt
-from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
-
-from .Ui_ShowInstalledDialog import Ui_ShowInstalledDialog
-
-
-class ShowInstalledDialog(QDialog, Ui_ShowInstalledDialog):
-    """
-    Class implementing a dialog to show the modules installed on the connected device.
-    """
-
-    def __init__(self, devicePath, parent=None):
-        """
-        Constructor
-
-        @param devicePath path to the connected board
-        @type str
-        @param parent reference to the parent widget (defaults to None)
-        @type QWidget (optional)
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-
-        self.modulesList.clear()
-        deviceModules = circup.get_device_versions(devicePath)
-        for name, metadata in deviceModules.items():
-            QTreeWidgetItem(
-                self.modulesList,
-                [name, metadata.get("__version__", self.tr("unknown"))],
-            )
-
-        self.modulesList.sortItems(0, Qt.SortOrder.AscendingOrder)
-        self.modulesList.resizeColumnToContents(0)
-        self.modulesList.resizeColumnToContents(1)
--- a/src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.ui	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ShowInstalledDialog</class>
- <widget class="QDialog" name="ShowInstalledDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>500</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Installed Modules</string>
-  </property>
-  <property name="sizeGripEnabled">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QTreeWidget" name="modulesList">
-     <property name="alternatingRowColors">
-      <bool>true</bool>
-     </property>
-     <property name="selectionMode">
-      <enum>QAbstractItemView::NoSelection</enum>
-     </property>
-     <property name="rootIsDecorated">
-      <bool>false</bool>
-     </property>
-     <property name="itemsExpandable">
-      <bool>false</bool>
-     </property>
-     <attribute name="headerShowSortIndicator" stdset="0">
-      <bool>false</bool>
-     </attribute>
-     <column>
-      <property name="text">
-       <string>Module</string>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>Version</string>
-      </property>
-     </column>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>ShowInstalledDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>ShowInstalledDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
--- a/src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,156 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to show outdated modules of a connected device.
-"""
-
-import circup
-
-from PyQt6.QtCore import Qt, pyqtSlot
-from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QTreeWidgetItem
-from semver import VersionInfo
-
-from .Ui_ShowOutdatedDialog import Ui_ShowOutdatedDialog
-
-
-class ShowOutdatedDialog(QDialog, Ui_ShowOutdatedDialog):
-    """
-    Class implementing a dialog to show outdated modules of a connected device.
-    """
-
-    def __init__(self, devicePath, selectionMode=False, parent=None):
-        """
-        Constructor
-
-        @param devicePath path to the connected board
-        @type str
-        @param selectionMode flag indicating the activation of the selection mode
-            (defaults to False)
-        @type bool (optional)
-        @param parent reference to the parent widget (defaults to None)
-        @type QWidget (optional)
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-
-        self.header.clear()
-        self.modulesList.clear()
-
-        self.__checkCount = 0
-        self.__selectionMode = selectionMode
-        if self.__selectionMode:
-            self.buttonBox.setStandardButtons(
-                QDialogButtonBox.StandardButton.Ok
-                | QDialogButtonBox.StandardButton.Cancel
-            )
-        else:
-            self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close)
-
-        self.__modules = {
-            m.name: m
-            for m in circup.find_modules(devicePath, circup.get_bundles_list())
-            if m.outofdate
-        }
-        if self.__modules:
-            self.header.setText(
-                self.tr(
-                    "The following modules are out of date or probably need an update."
-                    "\nMajor Updates may include breaking changes. Review before"
-                    " updating.\nMPY Format changes require an update."
-                )
-            )
-            for module in self.__modules.values():
-                if isinstance(module.bundle_version, str) and not VersionInfo.isvalid(
-                    module.bundle_version
-                ):
-                    reason = self.tr("Incorrect '__version__' Metadata")
-                    needsUpdate = True
-                elif module.bad_format:
-                    reason = self.tr("Corrupted or Unknown MPY Format")
-                    needsUpdate = True
-                elif module.mpy_mismatch:
-                    reason = self.tr("MPY Format")
-                    needsUpdate = True
-                elif module.major_update:
-                    reason = self.tr("Major Version")
-                    needsUpdate = False
-                else:
-                    reason = self.tr("Minor Version")
-                    needsUpdate = False
-                itm = QTreeWidgetItem(
-                    self.modulesList,
-                    [
-                        module.name,
-                        module.device_version
-                        if module.device_version
-                        else self.tr("unknown"),
-                        module.bundle_version
-                        if module.bundle_version
-                        else self.tr("unknown"),
-                        reason,
-                    ],
-                )
-                if self.__selectionMode:
-                    itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable)
-                    itm.setCheckState(
-                        0,
-                        Qt.CheckState.Checked
-                        if needsUpdate
-                        else Qt.CheckState.Unchecked,
-                    )
-                    if needsUpdate:
-                        self.__checkCount += 1
-        else:
-            self.header.setText(self.tr("All modules are up-to-date."))
-
-        self.modulesList.sortItems(0, Qt.SortOrder.AscendingOrder)
-        for column in range(self.modulesList.columnCount()):
-            self.modulesList.resizeColumnToContents(column)
-
-        self.__checkCountUpdated()
-
-    @pyqtSlot(QTreeWidgetItem, int)
-    def on_modulesList_itemChanged(self, item, column):
-        """
-        Private slot to handle a change of the check state of an item.
-
-        @param item reference to the changed item
-        @type QTreeWidgetItem
-        @param column changed column
-        @type int
-        """
-        if self.__selectionMode:
-            if item.checkState(0) == Qt.CheckState.Checked:
-                self.__checkCount += 1
-            else:
-                self.__checkCount -= 1
-
-            self.__checkCountUpdated()
-
-    def __checkCountUpdated(self):
-        """
-        Private method to handle an update of the check count.
-        """
-        if self.__selectionMode:
-            self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(
-                self.__checkCount > 0
-            )
-
-    def getSelection(self):
-        """
-        Public method to get the list of selected modules.
-
-        @return list of selected modules
-        @rtype circup.Module
-        """
-        results = []
-        if self.__selectionMode:
-            for row in range(self.modulesList.topLevelItemCount()):
-                itm = self.modulesList.topLevelItem(row)
-                if itm.checkState(0) == Qt.CheckState.Checked:
-                    results.append(self.__modules[itm.text(0)])
-
-        return results
--- a/src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.ui	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ShowOutdatedDialog</class>
- <widget class="QDialog" name="ShowOutdatedDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>500</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Outdated Modules</string>
-  </property>
-  <property name="sizeGripEnabled">
-   <bool>true</bool>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QLabel" name="header">
-     <property name="wordWrap">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QTreeWidget" name="modulesList">
-     <property name="alternatingRowColors">
-      <bool>true</bool>
-     </property>
-     <property name="selectionMode">
-      <enum>QAbstractItemView::NoSelection</enum>
-     </property>
-     <property name="rootIsDecorated">
-      <bool>false</bool>
-     </property>
-     <property name="itemsExpandable">
-      <bool>false</bool>
-     </property>
-     <attribute name="headerShowSortIndicator" stdset="0">
-      <bool>false</bool>
-     </attribute>
-     <column>
-      <property name="text">
-       <string>Module</string>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>Version</string>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>Latest</string>
-      </property>
-     </column>
-     <column>
-      <property name="text">
-       <string>Update Reason</string>
-      </property>
-     </column>
-    </widget>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Close</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>ShowOutdatedDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>ShowOutdatedDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
--- a/src/eric7/MicroPython/CircuitPythonUpdater/__init__.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Package implementing the updater and associated dialogs.
-"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonDevices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,535 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for CircuitPython boards.
+"""
+
+import os
+import shutil
+
+from PyQt6.QtCore import QProcess, QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
+from PyQt6.QtWidgets import QMenu
+
+from eric7 import Globals, Preferences
+from eric7.EricWidgets import EricFileDialog, EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+from eric7.SystemUtilities import FileSystemUtilities
+
+from .CircuitPythonUpdater.CircuitPythonUpdaterInterface import (
+    CircuitPythonUpdaterInterface,
+    isCircupAvailable,
+)
+from . import FirmwareGithubUrls
+from .DeviceBase import BaseDevice
+from ..MicroPythonWidget import HAS_QTCHART
+
+
+class CircuitPythonDevice(BaseDevice):
+    """
+    Class implementing the device for CircuitPython boards.
+    """
+
+    DeviceVolumeName = "CIRCUITPY"
+
+    def __init__(self, microPythonWidget, deviceType, boardName, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param boardName name of the board
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__boardName = boardName
+        self.__workspace = self.__findWorkspace()
+
+        self.__updater = CircuitPythonUpdaterInterface(self)
+
+        self.__createCPyMenu()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+        if self.__deviceVolumeMounted():
+            self.microPython.setActionButtons(open=True, save=True)
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return False
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.tr("CircuitPython")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def supportsLocalFileAccess(self):
+        """
+        Public method to indicate file access via a local directory.
+
+        @return flag indicating file access via local directory
+        @rtype bool
+        """
+        return self.__deviceVolumeMounted()
+
+    def __deviceVolumeMounted(self):
+        """
+        Private method to check, if the device volume is mounted.
+
+        @return flag indicated a mounted device
+        @rtype bool
+        """
+        if self.__workspace and not os.path.exists(self.__workspace):
+            self.__workspace = ""  # reset
+
+        return self.DeviceVolumeName in self.getWorkspace(silent=True)
+
+    def __findDeviceDirectories(self, directories):
+        """
+        Private method to find the device directories associated with the
+        current board name.
+
+        @param directories list of directories to be checked
+        @type list of str
+        @return list of associated directories
+        @rtype list of str
+        """
+        boardDirectories = []
+        for directory in directories:
+            bootFile = os.path.join(directory, "boot_out.txt")
+            if os.path.exists(bootFile):
+                with open(bootFile, "r") as f:
+                    line = f.readline()
+                if self.__boardName in line:
+                    boardDirectories.append(directory)
+
+        return boardDirectories
+
+    def __findWorkspace(self, silent=False):
+        """
+        Private method to find the workspace directory.
+
+        @param silent flag indicating silent operations
+        @type bool
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        # Attempts to find the paths on the filesystem that represents the
+        # plugged in CIRCUITPY boards.
+        deviceDirectories = FileSystemUtilities.findVolume(
+            self.DeviceVolumeName, findAll=True
+        )
+
+        if deviceDirectories:
+            if len(deviceDirectories) == 1:
+                return deviceDirectories[0]
+            else:
+                boardDirectories = self.__findDeviceDirectories(deviceDirectories)
+                if len(boardDirectories) == 1:
+                    return boardDirectories[0]
+                elif len(boardDirectories) > 1:
+                    return self.selectDeviceDirectory(boardDirectories)
+                else:
+                    return self.selectDeviceDirectory(deviceDirectories)
+        else:
+            # return the default workspace and give the user a warning (unless
+            # silent mode is selected)
+            if not silent:
+                EricMessageBox.warning(
+                    self.microPython,
+                    self.tr("Workspace Directory"),
+                    self.tr(
+                        "Python files for CircuitPython can be edited in"
+                        " place, if the device volume is locally"
+                        " available. Such a volume was not found. In"
+                        " place editing will not be available."
+                    ),
+                )
+
+            return super().getWorkspace()
+
+    def getWorkspace(self, silent=False):
+        """
+        Public method to get the workspace directory.
+
+        @param silent flag indicating silent operations
+        @type bool
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        if self.__workspace:
+            # return cached entry
+            return self.__workspace
+        else:
+            self.__workspace = self.__findWorkspace(silent=silent)
+            return self.__workspace
+
+    def __createCPyMenu(self):
+        """
+        Private method to create the CircuitPython submenu.
+        """
+        self.__libraryMenu = QMenu(self.tr("Library Management"))
+        self.__libraryMenu.aboutToShow.connect(self.__aboutToShowLibraryMenu)
+        self.__libraryMenu.setTearOffEnabled(True)
+
+        self.__cpyMenu = QMenu(self.tr("CircuitPython Functions"))
+
+        self.__cpyMenu.addAction(
+            self.tr("Show CircuitPython Versions"), self.__showCircuitPythonVersions
+        )
+        self.__cpyMenu.addSeparator()
+
+        boardName = self.microPython.getCurrentBoard()
+        lBoardName = boardName.lower() if boardName else ""
+        if "teensy" in lBoardName:
+            # Teensy 4.0 and 4.1 don't support UF2 flashing
+            self.__cpyMenu.addAction(
+                self.tr("CircuitPython Flash Instructions"),
+                self.__showTeensyFlashInstructions,
+            )
+            self.__flashCpyAct = self.__cpyMenu.addAction(
+                self.tr("Flash CircuitPython Firmware"), self.__startTeensyLoader
+            )
+            self.__flashCpyAct.setToolTip(
+                self.tr(
+                    "Start the 'Teensy Loader' application to flash the Teensy device."
+                )
+            )
+        else:
+            self.__flashCpyAct = self.__cpyMenu.addAction(
+                self.tr("Flash CircuitPython Firmware"), self.__flashCircuitPython
+            )
+        self.__cpyMenu.addSeparator()
+        self.__cpyMenu.addMenu(self.__libraryMenu)
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        linkConnected = self.microPython.isLinkConnected()
+
+        self.__flashCpyAct.setEnabled(not linkConnected)
+
+        menu.addMenu(self.__cpyMenu)
+
+    @pyqtSlot()
+    def __aboutToShowLibraryMenu(self):
+        """
+        Private slot to populate the 'Library Management' menu.
+        """
+        self.__libraryMenu.clear()
+
+        if isCircupAvailable():
+            self.__updater.populateMenu(self.__libraryMenu)
+        else:
+            act = self.__libraryMenu.addAction(
+                self.tr("Install Library Files"), self.__installLibraryFiles
+            )
+            act.setEnabled(self.__deviceVolumeMounted())
+            act = self.__libraryMenu.addAction(
+                self.tr("Install Library Package"),
+                lambda: self.__installLibraryFiles(packageMode=True),
+            )
+            act.setEnabled(self.__deviceVolumeMounted())
+            self.__libraryMenu.addSeparator()
+            self.__libraryMenu.addAction(
+                self.tr("Install 'circup' Package"),
+                self.__updater.installCircup,
+            )
+
+    def hasFlashMenuEntry(self):
+        """
+        Public method to check, if the device has its own flash menu entry.
+
+        @return flag indicating a specific flash menu entry
+        @rtype bool
+        """
+        return True
+
+    @pyqtSlot()
+    def __flashCircuitPython(self):
+        """
+        Private slot to flash a CircuitPython firmware to a device supporting UF2.
+        """
+        from ..UF2FlashDialog import UF2FlashDialog
+
+        dlg = UF2FlashDialog(boardType="circuitpython")
+        dlg.exec()
+
+    def __showTeensyFlashInstructions(self):
+        """
+        Private method to show a message box because Teensy does not support
+        the UF2 bootloader yet.
+        """
+        EricMessageBox.information(
+            self.microPython,
+            self.tr("Flash CircuitPython Firmware"),
+            self.tr(
+                """<p>Teensy 4.0 and Teensy 4.1 do not support the UF2"""
+                """ bootloader. Please use the 'Teensy Loader'"""
+                """ application to flash CircuitPython. Make sure you"""
+                """ downloaded the CircuitPython .hex file.</p>"""
+                """<p>See <a href="{0}">the PJRC Teensy web site</a>"""
+                """ for details.</p>"""
+            ).format("https://www.pjrc.com/teensy/loader.html"),
+        )
+
+    def __startTeensyLoader(self):
+        """
+        Private method to start the 'Teensy Loader' application.
+
+        Note: The application must be accessible via the application search path.
+        """
+        ok, _ = QProcess.startDetached("teensy")
+        if not ok:
+            EricMessageBox.warning(
+                self.microPython,
+                self.tr("Start 'Teensy Loader'"),
+                self.tr(
+                    """<p>The 'Teensy Loader' application <b>teensy</b> could not"""
+                    """ be started. Ensure it is in the application search path or"""
+                    """ start it manually.</p>"""
+                ),
+            )
+
+    @pyqtSlot()
+    def __showCircuitPythonVersions(self):
+        """
+        Private slot to show the CircuitPython version of a connected device and
+        the latest available one (from Github).
+        """
+        ui = ericApp().getObject("UserInterface")
+        request = QNetworkRequest(QUrl(FirmwareGithubUrls["circuitpython"]))
+        reply = ui.networkAccessManager().head(request)
+        reply.finished.connect(lambda: self.__cpyVersionResponse(reply))
+
+    def __cpyVersionResponse(self, reply):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        """
+        latestUrl = reply.url().toString()
+        tag = latestUrl.rsplit("/", 1)[-1]
+        latestVersion = Globals.versionToTuple(tag)
+
+        cpyVersionStr = self.tr("unknown")
+        cpyVersion = (0, 0, 0)
+        if self.supportsLocalFileAccess():
+            bootFile = os.path.join(self.getWorkspace(), "boot_out.txt")
+            if os.path.exists(bootFile):
+                with open(bootFile, "r") as f:
+                    line = f.readline()
+                cpyVersionStr = line.split(";")[0].split()[2]
+                cpyVersion = Globals.versionToTuple(cpyVersionStr)
+        if (
+            cpyVersion == (0, 0, 0)
+            and self._deviceData
+            and self._deviceData["mpy_version"] != "unknown"
+        ):
+            # drive is not mounted or 'boot_out.txt' is missing but the device
+            # is connected via the serial console
+            cpyVersionStr = self._deviceData["mpy_version"]
+            cpyVersion = Globals.versionToTuple(cpyVersionStr)
+
+        msg = self.tr(
+            "<h4>CircuitPython Version Information</h4>"
+            "<table>"
+            "<tr><td>Installed:</td><td>{0}</td></tr>"
+            "<tr><td>Available:</td><td>{1}</td></tr>"
+            "</table>"
+        ).format(cpyVersionStr, tag)
+        if cpyVersion < latestVersion and cpyVersion != (0, 0, 0):
+            msg += self.tr("<p><b>Update available!</b></p>")
+
+        EricMessageBox.information(
+            None,
+            self.tr("CircuitPython Version"),
+            msg,
+        )
+
+    @pyqtSlot()
+    def __installLibraryFiles(self, packageMode=False):
+        """
+        Private slot to install Python files into the onboard library.
+
+        @param packageMode flag indicating to install a library package
+            (defaults to False)
+        @type bool (optional)
+        """
+        title = (
+            self.tr("Install Library Package")
+            if packageMode
+            else self.tr("Install Library Files")
+        )
+        if not self.__deviceVolumeMounted():
+            EricMessageBox.critical(
+                self.microPython,
+                title,
+                self.tr(
+                    """The device volume "<b>{0}</b>" is not available."""
+                    """ Ensure it is mounted properly and try again."""
+                ),
+            )
+            return
+
+        target = os.path.join(self.getWorkspace(), "lib")
+        # ensure that the library directory exists on the device
+        if not os.path.isdir(target):
+            os.makedirs(target)
+
+        if packageMode:
+            libraryPackage = EricFileDialog.getExistingDirectory(
+                self.microPython,
+                title,
+                os.path.expanduser("~"),
+                EricFileDialog.Option(0),
+            )
+            if libraryPackage:
+                target = os.path.join(target, os.path.basename(libraryPackage))
+                shutil.rmtree(target, ignore_errors=True)
+                shutil.copytree(libraryPackage, target)
+        else:
+            libraryFiles = EricFileDialog.getOpenFileNames(
+                self.microPython,
+                title,
+                os.path.expanduser("~"),
+                self.tr(
+                    "Compiled Python Files (*.mpy);;"
+                    "Python Files (*.py);;"
+                    "All Files (*)"
+                ),
+            )
+
+            for libraryFile in libraryFiles:
+                if os.path.exists(libraryFile):
+                    shutil.copy2(libraryFile, target)
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("CircuitPythonDocuUrl")
+
+    def getDownloadMenuEntries(self):
+        """
+        Public method to retrieve the entries for the downloads menu.
+
+        @return list of tuples with menu text and URL to be opened for each
+            entry
+        @rtype list of tuple of (str, str)
+        """
+        return [
+            (
+                self.tr("CircuitPython Firmware"),
+                Preferences.getMicroPython("CircuitPythonFirmwareUrl"),
+            ),
+            (
+                self.tr("CircuitPython Libraries"),
+                Preferences.getMicroPython("CircuitPythonLibrariesUrl"),
+            ),
+        ]
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype CircuitPythonDevice
+    """
+    return CircuitPythonDevice(microPythonWidget, deviceType, boardName)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,668 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing an interface to the 'circup' package.
+"""
+
+import importlib
+import logging
+import os
+import re
+import shutil
+
+import requests
+
+from PyQt6.QtCore import QObject, pyqtSlot
+from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit, QMenu
+
+from eric7 import Preferences
+from eric7.EricGui.EricOverrideCursor import EricOverrideCursor
+from eric7.EricWidgets import EricFileDialog, EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog
+from eric7.SystemUtilities import PythonUtilities
+
+try:
+    import circup
+
+    circup.logger.setLevel(logging.WARNING)
+except ImportError:
+    circup = None
+
+
+class CircuitPythonUpdaterInterface(QObject):
+    """
+    Class implementing an interface to the 'circup' package.
+    """
+
+    def __init__(self, device, parent=None):
+        """
+        Constructor
+
+        @param device reference to the CircuitPython device interface
+        @type CircuitPythonDevice
+        @param parent reference to the parent object (defaults to None)
+        @type QObject (optional)
+        """
+        super().__init__(parent)
+
+        self.__device = device
+
+        self.__installMenu = QMenu(self.tr("Install Modules"))
+        self.__installMenu.setTearOffEnabled(True)
+        self.__installMenu.addAction(
+            self.tr("Select from Available Modules"), self.__installFromAvailable
+        )
+        self.__installMenu.addAction(
+            self.tr("Install Requirements"), self.__installRequirements
+        )
+        self.__installMenu.addAction(
+            self.tr("Install based on 'code.py'"), self.__installFromCode
+        )
+        self.__installMenu.addSeparator()
+        self.__installPyAct = self.__installMenu.addAction(
+            self.tr("Install Python Source")
+        )
+        self.__installPyAct.setCheckable(True)
+        self.__installPyAct.setChecked(False)
+        # kind of hack to make this action not hide the menu
+        # Note: parent menus are hidden nevertheless
+        self.__installPyAct.toggled.connect(self.__installMenu.show)
+
+    def populateMenu(self, menu):
+        """
+        Public method to populate the 'circup' menu.
+
+        @param menu reference to the menu to be populated
+        @type QMenu
+        """
+        from .CircupFunctions import patch_circup
+
+        patch_circup()
+        isMounted = self.__device.supportsLocalFileAccess()
+
+        act = menu.addAction(self.tr("circup"), self.__aboutCircup)
+        font = act.font()
+        font.setBold(True)
+        act.setFont(font)
+        menu.addSeparator()
+        menu.addAction(
+            self.tr("List Outdated Modules"), self.__listOutdatedModules
+        ).setEnabled(isMounted)
+        menu.addAction(self.tr("Update Modules"), self.__updateModules).setEnabled(
+            isMounted
+        )
+        menu.addAction(
+            self.tr("Update All Modules"), self.__updateAllModules
+        ).setEnabled(isMounted)
+        menu.addSeparator()
+        menu.addAction(self.tr("Show Available Modules"), self.__showAvailableModules)
+        menu.addAction(
+            self.tr("Show Installed Modules"), self.__showInstalledModules
+        ).setEnabled(isMounted)
+        menu.addMenu(self.__installMenu).setEnabled(isMounted)
+        menu.addAction(
+            self.tr("Uninstall Modules"), self.__uninstallModules
+        ).setEnabled(isMounted)
+        menu.addSeparator()
+        menu.addAction(
+            self.tr("Generate Requirements ..."), self.__generateRequirements
+        ).setEnabled(isMounted)
+        menu.addSeparator()
+        menu.addAction(self.tr("Show Bundles"), self.__showBundles)
+        menu.addAction(self.tr("Show Bundles with Modules"), self.__showBundlesModules)
+        menu.addSeparator()
+        menu.addAction(self.tr("Add Bundle"), self.__addBundle)
+        menu.addAction(self.tr("Remove Bundles"), self.__removeBundle)
+
+    @pyqtSlot()
+    def __aboutCircup(self):
+        """
+        Private slot to show some info about 'circup'.
+        """
+        version = circup.get_circup_version()
+        if version is None:
+            version = self.tr("unknown")
+
+        EricMessageBox.information(
+            None,
+            self.tr("About circup"),
+            self.tr(
+                """<p><b>circup Version {0}</b></p>"""
+                """<p><i>circup</i> is a tool to manage and update libraries on a"""
+                """ CircuitPython device.</p>""",
+            ).format(version),
+        )
+
+    @pyqtSlot()
+    def installCircup(self):
+        """
+        Public slot to install the 'circup' package via pip.
+        """
+        global circup
+
+        pip = ericApp().getObject("Pip")
+        pip.installPackages(
+            ["circup"], interpreter=PythonUtilities.getPythonExecutable()
+        )
+
+        circup = importlib.import_module("circup")
+        circup.logger.setLevel(logging.WARNING)
+
+    @pyqtSlot()
+    def __showBundles(self, withModules=False):
+        """
+        Private slot to show the available bundles (default and local).
+
+        @param withModules flag indicating to list the modules and their version
+            (defaults to False)
+        @type bool (optional)
+        """
+        from .ShowBundlesDialog import ShowBundlesDialog
+
+        with EricOverrideCursor():
+            dlg = ShowBundlesDialog(withModules=withModules)
+        dlg.exec()
+
+    @pyqtSlot()
+    def __showBundlesModules(self):
+        """
+        Private slot to show the available bundles (default and local) with their
+        modules.
+        """
+        self.__showBundles(withModules=True)
+
+    @pyqtSlot()
+    def __addBundle(self):
+        """
+        Private slot to add a bundle to the local bundles list, by "user/repo" github
+        string.
+        """
+        bundle, ok = QInputDialog.getText(
+            None,
+            self.tr("Add Bundle"),
+            self.tr("Enter Bundle by 'User/Repo' Github String:"),
+            QLineEdit.EchoMode.Normal,
+        )
+        if ok and bundle:
+            bundles = circup.get_bundles_local_dict()
+            modified = False
+
+            # do some cleanup
+            bundle = re.sub(r"https?://github.com/([^/]+/[^/]+)(/.*)?", r"\1", bundle)
+            if bundle in bundles:
+                EricMessageBox.information(
+                    None,
+                    self.tr("Add Bundle"),
+                    self.tr(
+                        """<p>The bundle <b>{0}</b> is already in the list.</p>"""
+                    ).format(bundle),
+                )
+                return
+
+            try:
+                cBundle = circup.Bundle(bundle)
+            except ValueError:
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Add Bundle"),
+                    self.tr(
+                        """<p>The bundle string is invalid, expecting github URL"""
+                        """ or 'user/repository' string.</p>"""
+                    ),
+                )
+                return
+
+            result = requests.head("https://github.com/" + bundle)
+            if result.status_code == requests.codes.NOT_FOUND:
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Add Bundle"),
+                    self.tr(
+                        """<p>The bundle string is invalid. The repository doesn't"""
+                        """ exist (error code 404).</p>"""
+                    ),
+                )
+                return
+
+            if not cBundle.validate():
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Add Bundle"),
+                    self.tr(
+                        """<p>The bundle string is invalid. Is the repository a valid"""
+                        """ circup bundle?</p>"""
+                    ),
+                )
+                return
+
+            # Use the bundle string as the dictionary key for uniqueness
+            bundles[bundle] = bundle
+            modified = True
+            EricMessageBox.information(
+                None,
+                self.tr("Add Bundle"),
+                self.tr("""<p>Added bundle <b>{0}</b> ({1}).</p>""").format(
+                    bundle, cBundle.url
+                ),
+            )
+
+            if modified:
+                # save the bundles list
+                circup.save_local_bundles(bundles)
+                # update and get the new bundle for the first time
+                circup.get_bundle_versions(circup.get_bundles_list())
+
+    @pyqtSlot()
+    def __removeBundle(self):
+        """
+        Private slot to remove one or more bundles from the local bundles list.
+        """
+        localBundles = circup.get_bundles_local_dict()
+        dlg = EricListSelectionDialog(
+            sorted(localBundles.keys()),
+            title=self.tr("Remove Bundles"),
+            message=self.tr("Select the bundles to be removed:"),
+            checkBoxSelection=True,
+        )
+        modified = False
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            bundles = dlg.getSelection()
+            for bundle in bundles:
+                del localBundles[bundle]
+                modified = True
+
+        if modified:
+            circup.save_local_bundles(localBundles)
+            EricMessageBox.information(
+                None,
+                self.tr("Remove Bundles"),
+                self.tr(
+                    """<p>These bundles were removed from the local bundles list.{0}"""
+                    """</p>"""
+                ).format("""<ul><li>{0}</li></ul>""".format("</li><li>".join(bundles))),
+            )
+
+    @pyqtSlot()
+    def __listOutdatedModules(self):
+        """
+        Private slot to list the outdated modules of the connected device.
+        """
+        from .ShowOutdatedDialog import ShowOutdatedDialog
+
+        devicePath = self.__device.getWorkspace()
+
+        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
+        circup.CPY_VERSION = cpyVersion
+
+        with EricOverrideCursor():
+            dlg = ShowOutdatedDialog(devicePath=devicePath)
+        dlg.exec()
+
+    @pyqtSlot()
+    def __updateModules(self):
+        """
+        Private slot to update the modules of the connected device.
+        """
+        from .ShowOutdatedDialog import ShowOutdatedDialog
+
+        devicePath = self.__device.getWorkspace()
+
+        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
+        circup.CPY_VERSION = cpyVersion
+
+        with EricOverrideCursor():
+            dlg = ShowOutdatedDialog(devicePath=devicePath, selectionMode=True)
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            modules = dlg.getSelection()
+            self.__doUpdateModules(modules)
+
+    @pyqtSlot()
+    def __updateAllModules(self):
+        """
+        Private slot to update all modules of the connected device.
+        """
+        devicePath = self.__device.getWorkspace()
+
+        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
+        circup.CPY_VERSION = cpyVersion
+
+        with EricOverrideCursor():
+            modules = [
+                m
+                for m in circup.find_modules(devicePath, circup.get_bundles_list())
+                if m.outofdate
+            ]
+        if modules:
+            self.__doUpdateModules(modules)
+        else:
+            EricMessageBox.information(
+                None,
+                self.tr("Update Modules"),
+                self.tr("All modules are already up-to-date."),
+            )
+
+    def __doUpdateModules(self, modules):
+        """
+        Private method to perform the update of a list of modules.
+
+        @param modules list of modules to be updated
+        @type circup.Module
+        """
+        updatedModules = []
+        for module in modules:
+            try:
+                module.update()
+                updatedModules.append(module.name)
+            except Exception as ex:
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Update Modules"),
+                    self.tr(
+                        """<p>There was an error updating <b>{0}</b>.</p>"""
+                        """<p>Error: {1}</p>"""
+                    ).format(module.name, str(ex)),
+                )
+
+        if updatedModules:
+            EricMessageBox.information(
+                None,
+                self.tr("Update Modules"),
+                self.tr(
+                    """<p>These modules were updated on the connected device.{0}</p>"""
+                ).format(
+                    """<ul><li>{0}</li></ul>""".format("</li><li>".join(updatedModules))
+                ),
+            )
+        else:
+            EricMessageBox.information(
+                None,
+                self.tr("Update Modules"),
+                self.tr("No modules could be updated."),
+            )
+
+    @pyqtSlot()
+    def __showAvailableModules(self):
+        """
+        Private slot to show the available modules.
+
+        These are modules which could be installed on the device.
+        """
+        from ..ShowModulesDialog import ShowModulesDialog
+
+        with EricOverrideCursor():
+            availableModules = circup.get_bundle_versions(circup.get_bundles_list())
+            moduleNames = [m.replace(".py", "") for m in availableModules]
+
+        dlg = ShowModulesDialog(moduleNames)
+        dlg.exec()
+
+    @pyqtSlot()
+    def __showInstalledModules(self):
+        """
+        Private slot to show the modules installed on the connected device.
+        """
+        from .ShowInstalledDialog import ShowInstalledDialog
+
+        devicePath = self.__device.getWorkspace()
+
+        with EricOverrideCursor():
+            dlg = ShowInstalledDialog(devicePath=devicePath)
+        dlg.exec()
+
+    @pyqtSlot()
+    def __installFromAvailable(self):
+        """
+        Private slot to install modules onto the connected device.
+        """
+        from ..ShowModulesDialog import ShowModulesDialog
+
+        with EricOverrideCursor():
+            availableModules = circup.get_bundle_versions(circup.get_bundles_list())
+            moduleNames = [m.replace(".py", "") for m in availableModules]
+
+        dlg = ShowModulesDialog(moduleNames, selectionMode=True)
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            modules = dlg.getSelection()
+            self.__installModules(modules)
+
+    @pyqtSlot()
+    def __installRequirements(self):
+        """
+        Private slot to install modules determined by a requirements file.
+        """
+        homeDir = (
+            Preferences.getMicroPython("MpyWorkspace")
+            or Preferences.getMultiProject("Workspace")
+            or os.path.expanduser("~")
+        )
+        reqFile = EricFileDialog.getOpenFileName(
+            None,
+            self.tr("Install Modules"),
+            homeDir,
+            self.tr("Text Files (*.txt);;All Files (*)"),
+        )
+        if reqFile:
+            if os.path.exists(reqFile):
+                with open(reqFile, "r") as fp:
+                    requirementsText = fp.read()
+                modules = circup.libraries_from_requirements(requirementsText)
+                if modules:
+                    self.__installModules(modules)
+                else:
+                    EricMessageBox.critical(
+                        None,
+                        self.tr("Install Modules"),
+                        self.tr(
+                            """<p>The given requirements file <b>{0}</b> does not"""
+                            """ contain valid modules.</p>"""
+                        ).format(reqFile),
+                    )
+            else:
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Install Modules"),
+                    self.tr(
+                        """<p>The given requirements file <b>{0}</b> does not exist."""
+                        """</p>"""
+                    ).format(reqFile),
+                )
+
+    @pyqtSlot()
+    def __installFromCode(self):
+        """
+        Private slot to install modules based on the 'code.py' file of the
+        connected device.
+        """
+        devicePath = self.__device.getWorkspace()
+
+        codeFile = EricFileDialog.getOpenFileName(
+            None,
+            self.tr("Install Modules"),
+            os.path.join(devicePath, "code.py"),
+            self.tr("Python Files (*.py);;All Files (*)"),
+        )
+        if codeFile:
+            if os.path.exists(codeFile):
+                with EricOverrideCursor():
+                    availableModules = circup.get_bundle_versions(
+                        circup.get_bundles_list()
+                    )
+                    moduleNames = {}
+                    for module, metadata in availableModules.items():
+                        moduleNames[module.replace(".py", "")] = metadata
+
+                modules = circup.libraries_from_imports(codeFile, moduleNames)
+                if modules:
+                    self.__installModules(modules)
+                else:
+                    EricMessageBox.critical(
+                        None,
+                        self.tr("Install Modules"),
+                        self.tr(
+                            """<p>The given code file <b>{0}</b> does not"""
+                            """ contain valid import statements or does not import"""
+                            """ external modules.</p>"""
+                        ).format(codeFile),
+                    )
+            else:
+                EricMessageBox.critical(
+                    None,
+                    self.tr("Install Modules"),
+                    self.tr(
+                        """<p>The given code file <b>{0}</b> does not exist.</p>"""
+                    ).format(codeFile),
+                )
+
+    def __installModules(self, installs):
+        """
+        Private method to install the given list of modules.
+
+        @param installs list of module names to be installed
+        @type list of str
+        """
+        devicePath = self.__device.getWorkspace()
+
+        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
+        circup.CPY_VERSION = cpyVersion
+
+        with EricOverrideCursor():
+            availableModules = circup.get_bundle_versions(circup.get_bundles_list())
+            moduleNames = {}
+            for module, metadata in availableModules.items():
+                moduleNames[module.replace(".py", "")] = metadata
+            toBeInstalled = circup.get_dependencies(installs, mod_names=moduleNames)
+            deviceModules = circup.get_device_versions(devicePath)
+        if toBeInstalled is not None:
+            dependencies = [m for m in toBeInstalled if m not in installs]
+            ok = EricMessageBox.yesNo(
+                None,
+                self.tr("Install Modules"),
+                self.tr("""<p>Ready to install these modules?{0}{1}</p>""").format(
+                    """<ul><li>{0}</li></ul>""".format(
+                        "</li><li>".join(sorted(installs))
+                    ),
+                    self.tr("Dependencies:")
+                    + """<ul><li>{0}</li></ul>""".format(
+                        "</li><li>".join(sorted(dependencies))
+                    )
+                    if dependencies
+                    else "",
+                ),
+                yesDefault=True,
+            )
+            if ok:
+                installedModules = []
+                with EricOverrideCursor():
+                    for library in toBeInstalled:
+                        success = circup.install_module(
+                            devicePath,
+                            deviceModules,
+                            library,
+                            self.__installPyAct.isChecked(),
+                            moduleNames,
+                        )
+                        if success:
+                            installedModules.append(library)
+
+                if installedModules:
+                    EricMessageBox.information(
+                        None,
+                        self.tr("Install Modules"),
+                        self.tr(
+                            "<p>Installation complete. These modules were installed"
+                            " successfully.{0}</p>"
+                        ).format(
+                            """<ul><li>{0}</li></ul>""".format(
+                                "</li><li>".join(sorted(installedModules))
+                            ),
+                        ),
+                    )
+                else:
+                    EricMessageBox.information(
+                        None,
+                        self.tr("Install Modules"),
+                        self.tr(
+                            "<p>Installation complete. No modules were installed.</p>"
+                        ),
+                    )
+        else:
+            EricMessageBox.information(
+                None,
+                self.tr("Install Modules"),
+                self.tr("<p>No modules installation is required.</p>"),
+            )
+
+    @pyqtSlot()
+    def __uninstallModules(self):
+        """
+        Private slot to uninstall modules from the connected device.
+        """
+        devicePath = self.__device.getWorkspace()
+        libraryPath = os.path.join(devicePath, "lib")
+
+        with EricOverrideCursor():
+            deviceModules = circup.get_device_versions(devicePath)
+        modNames = {}
+        for moduleItem, metadata in deviceModules.items():
+            modNames[moduleItem.replace(".py", "").lower()] = metadata
+
+        dlg = EricListSelectionDialog(
+            sorted(modNames.keys()),
+            title=self.tr("Uninstall Modules"),
+            message=self.tr("Select the modules/packages to be uninstalled:"),
+            checkBoxSelection=True,
+        )
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            names = dlg.getSelection()
+            for name in names:
+                modulePath = modNames[name]["path"]
+                if os.path.isdir(modulePath):
+                    target = os.path.basename(os.path.dirname(modulePath))
+                    targetPath = os.path.join(libraryPath, target)
+                    # Remove the package directory.
+                    shutil.rmtree(targetPath)
+                else:
+                    target = os.path.basename(modulePath)
+                    targetPath = os.path.join(libraryPath, target)
+                    # Remove the module file
+                    os.remove(targetPath)
+
+            EricMessageBox.information(
+                None,
+                self.tr("Uninstall Modules"),
+                self.tr(
+                    """<p>These modules/packages were uninstalled from the connected"""
+                    """ device.{0}</p>"""
+                ).format("""<ul><li>{0}</li></ul>""".format("</li><li>".join(names))),
+            )
+
+    @pyqtSlot()
+    def __generateRequirements(self):
+        """
+        Private slot to generate requirements for the connected device.
+        """
+        from .RequirementsDialog import RequirementsDialog
+
+        devicePath = self.__device.getWorkspace()
+
+        cpyVersion, board_id = circup.get_circuitpython_version(devicePath)
+        circup.CPY_VERSION = cpyVersion
+
+        dlg = RequirementsDialog(devicePath=devicePath)
+        dlg.exec()
+
+
+def isCircupAvailable():
+    """
+    Function to check for the availability of 'circup'.
+
+    @return flag indicating the availability of 'circup'
+    @rtype bool
+    """
+    global circup
+
+    return circup is not None
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/CircupFunctions.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing variants of some 'circup' functions suitable for 'eric-ide'
+integration.
+"""
+
+#
+# Copyright of the original sources:
+# Copyright (c) 2019 Adafruit Industries
+#
+
+import os
+import shutil
+
+import circup
+import requests
+
+from PyQt6.QtCore import QCoreApplication
+
+from eric7.EricWidgets import EricMessageBox
+
+
+def find_modules(device_path, bundles_list):
+    """
+    Function to extract metadata from the connected device and available bundles and
+    returns this as a list of Module instances representing the modules on the device.
+
+    @param device_path path to the connected board
+    @type str
+    @param bundles_list list of supported bundles
+    @type list of circup.Bundle
+    @return list of Module instances describing the current state of the
+        modules on the connected device
+    @rtype list of circup.Module
+    """
+    result = []
+    try:
+        device_modules = circup.get_device_versions(device_path)
+        bundle_modules = circup.get_bundle_versions(bundles_list)
+        for name, device_metadata in device_modules.items():
+            if name in bundle_modules:
+                path = device_metadata["path"]
+                bundle_metadata = bundle_modules[name]
+                repo = bundle_metadata.get("__repo__")
+                bundle = bundle_metadata.get("bundle")
+                device_version = device_metadata.get("__version__")
+                bundle_version = bundle_metadata.get("__version__")
+                mpy = device_metadata["mpy"]
+                compatibility = device_metadata.get("compatibility", (None, None))
+                result.append(
+                    circup.Module(
+                        path,
+                        repo,
+                        device_version,
+                        bundle_version,
+                        mpy,
+                        bundle,
+                        compatibility,
+                    )
+                )
+    except Exception as ex:
+        # If it's not possible to get the device and bundle metadata, bail out
+        # with a friendly message and indication of what's gone wrong.
+        EricMessageBox.critical(
+            None,
+            QCoreApplication.translate("CircupFunctions", "Find Modules"),
+            QCoreApplication.translate(
+                "CircupFunctions", """<p>There was an error: {0}</p>"""
+            ).format(str(ex)),
+        )
+
+    return result
+
+
+def ensure_latest_bundle(bundle):
+    """
+    Function to ensure that there's a copy of the latest library bundle available so
+    circup can check the metadata contained therein.
+
+    @param bundle reference to the target Bundle object.
+    @type circup.Bundle
+    """
+    tag = bundle.latest_tag
+    do_update = False
+    if tag == bundle.current_tag:
+        for platform in circup.PLATFORMS:
+            # missing directories (new platform added on an existing install
+            # or side effect of pytest or network errors)
+            do_update = do_update or not os.path.isdir(bundle.lib_dir(platform))
+    else:
+        do_update = True
+
+    if do_update:
+        try:
+            circup.get_bundle(bundle, tag)
+            circup.tags_data_save_tag(bundle.key, tag)
+        except requests.exceptions.HTTPError as ex:
+            EricMessageBox.critical(
+                None,
+                QCoreApplication.translate("CircupFunctions", "Download Bundle"),
+                QCoreApplication.translate(
+                    "CircupFunctions",
+                    """<p>There was a problem downloading the bundle. Please try"""
+                    """ again in a moment.</p><p>Error: {0}</p>""",
+                ).format(str(ex)),
+            )
+
+
+def get_circuitpython_version(device_path):
+    """
+    Function to return the version number of CircuitPython running on the board
+    connected via ``device_path``, along with the board ID.
+
+    This is obtained from the 'boot_out.txt' file on the device, whose first line
+    will start with something like this:
+
+        Adafruit CircuitPython 4.1.0 on 2019-08-02;
+
+    While the second line is:
+
+        Board ID:raspberry_pi_pico
+
+    @param device_path path to the connected board.
+    @type str
+    @return tuple with the version string for CircuitPython and the board ID string
+    @rtype tuple of (str, str)
+    """
+    try:
+        with open(os.path.join(device_path, "boot_out.txt")) as boot:
+            version_line = boot.readline()
+            circuit_python = version_line.split(";")[0].split(" ")[-3]
+            board_line = boot.readline()
+            board_id = (
+                board_line[9:].strip() if board_line.startswith("Board ID:") else ""
+            )
+    except FileNotFoundError:
+        EricMessageBox.critical(
+            None,
+            QCoreApplication.translate("CircupFunctions", "Download Bundle"),
+            QCoreApplication.translate(
+                "CircupFunctions",
+                """<p>Missing file <b>boot_out.txt</b> on the device: wrong path or"""
+                """ drive corrupted.</p>""",
+            ),
+        )
+        circuit_python, board_id = "", ""
+
+    return (circuit_python, board_id)
+
+
+def install_module(device_path, device_modules, name, py, mod_names):
+    """
+    Function to find a connected device and install a given module name.
+
+    Installation is done if it is available in the current module bundle and is not
+    already installed on the device.
+
+    @param device_path path to the connected board
+    @type str
+    @param device_modules list of module metadata from the device
+    @type list of dict
+    @param name name of the module to be installed
+    @type str
+    @param py flag indicating if the module should be installed from source or
+        from a pre-compiled module
+    @type bool
+    @param mod_names dictionary containing metadata from modules that can be generated
+        with circup.get_bundle_versions()
+    @type dict
+    @return flag indicating success
+    @rtype bool
+    """
+    if not name:
+        return False
+    elif name in mod_names:
+        library_path = os.path.join(device_path, "lib")
+        if not os.path.exists(library_path):  # pragma: no cover
+            os.makedirs(library_path)
+        metadata = mod_names[name]
+        bundle = metadata["bundle"]
+        # Grab device modules to check if module already installed
+        if name in device_modules:
+            # ignore silently
+            return False
+        if py:
+            # Use Python source for module.
+            source_path = metadata["path"]  # Path to Python source version.
+            if os.path.isdir(source_path):
+                target = os.path.basename(os.path.dirname(source_path))
+                target_path = os.path.join(library_path, target)
+                # Copy the directory.
+                shutil.copytree(source_path, target_path)
+                return True
+            else:
+                target = os.path.basename(source_path)
+                target_path = os.path.join(library_path, target)
+                # Copy file.
+                shutil.copyfile(source_path, target_path)
+                return True
+        else:
+            # Use pre-compiled mpy modules.
+            module_name = os.path.basename(metadata["path"]).replace(".py", ".mpy")
+            if not module_name:
+                # Must be a directory based module.
+                module_name = os.path.basename(os.path.dirname(metadata["path"]))
+            major_version = circup.CPY_VERSION.split(".")[0]
+            bundle_platform = "{0}mpy".format(major_version)
+            bundle_path = os.path.join(bundle.lib_dir(bundle_platform), module_name)
+            if os.path.isdir(bundle_path):
+                target_path = os.path.join(library_path, module_name)
+                # Copy the directory.
+                shutil.copytree(bundle_path, target_path)
+                return True
+            elif os.path.isfile(bundle_path):
+                target = os.path.basename(bundle_path)
+                target_path = os.path.join(library_path, target)
+                # Copy file.
+                shutil.copyfile(bundle_path, target_path)
+                return True
+            else:
+                EricMessageBox.critical(
+                    None,
+                    QCoreApplication.translate("CircupFunctions", "Install Modules"),
+                    QCoreApplication.translate(
+                        "CircupFunctions",
+                        """<p>The compiled version of module <b>{0}</b> cannot be"""
+                        """ found.</p>""",
+                    ).format(name),
+                )
+                return False
+    else:
+        EricMessageBox.critical(
+            None,
+            QCoreApplication.translate("CircupFunctions", "Install Modules"),
+            QCoreApplication.translate(
+                "CircupFunctions", """<p>The module name <b>{0}</b> is not known.</p>"""
+            ).format(name),
+        )
+        return False
+
+
+def patch_circup():
+    """
+    Function to patch 'circup' to use our functions adapted to the use within the
+    eric-ide.
+    """
+    circup.ensure_latest_bundle = ensure_latest_bundle
+    circup.find_modules = find_modules
+    circup.get_circuitpython_version = get_circuitpython_version
+    circup.install_module = install_module
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/RequirementsDialog.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,265 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to generate a requirements file.
+"""
+
+import os
+
+import circup
+
+from PyQt6.QtCore import pyqtSlot
+from PyQt6.QtGui import QGuiApplication
+from PyQt6.QtWidgets import QAbstractButton, QDialog, QDialogButtonBox
+
+from eric7.EricWidgets import EricFileDialog, EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
+from eric7.SystemUtilities import FileSystemUtilities
+
+from .Ui_RequirementsDialog import Ui_RequirementsDialog
+
+
+class RequirementsDialog(QDialog, Ui_RequirementsDialog):
+    """
+    Class implementing a dialog to generate a requirements file.
+    """
+
+    def __init__(self, devicePath, parent=None):
+        """
+        Constructor
+
+        @param devicePath path to the connected board
+        @type str
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.__title = self.tr("Generate Requirements")
+
+        self.__refreshButton = self.buttonBox.addButton(
+            self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole
+        )
+
+        self.requirementsFilePicker.setMode(EricPathPickerModes.SAVE_FILE_MODE)
+        self.requirementsFilePicker.setFilters(
+            self.tr("Text Files (*.txt);;All Files (*)")
+        )
+
+        self.__devicePath = devicePath
+
+        self.__requirementsEdited = False
+        self.__requirementsAvailable = False
+
+        self.__generateRequirements()
+
+    def __updateButtons(self):
+        """
+        Private method to set the state of the various buttons.
+        """
+        self.saveButton.setEnabled(
+            self.__requirementsAvailable
+            and bool(self.requirementsFilePicker.text())
+            and os.path.isabs(self.requirementsFilePicker.text())
+        )
+        self.saveToButton.setEnabled(self.__requirementsAvailable)
+        self.copyButton.setEnabled(self.__requirementsAvailable)
+
+        aw = ericApp().getObject("ViewManager").activeWindow()
+        if aw and self.__requirementsAvailable:
+            self.insertButton.setEnabled(True)
+            self.replaceAllButton.setEnabled(True)
+            self.replaceSelectionButton.setEnabled(aw.hasSelectedText())
+        else:
+            self.insertButton.setEnabled(False)
+            self.replaceAllButton.setEnabled(False)
+            self.replaceSelectionButton.setEnabled(False)
+
+    @pyqtSlot(str)
+    def on_requirementsFilePicker_textChanged(self, txt):
+        """
+        Private slot handling a change of the requirements file name.
+
+        @param txt name of the requirements file
+        @type str
+        """
+        self.__updateButtons()
+
+    @pyqtSlot()
+    def on_requirementsEdit_textChanged(self):
+        """
+        Private slot handling changes of the requirements text.
+        """
+        self.__requirementsEdited = True
+
+    @pyqtSlot(QAbstractButton)
+    def on_buttonBox_clicked(self, button):
+        """
+        Private slot called by a button of the button box clicked.
+
+        @param button button that was clicked
+        @type QAbstractButton
+        """
+        if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close):
+            self.close()
+        elif button == self.__refreshButton:
+            self.__generateRequirements()
+
+    def __generateRequirements(self):
+        """
+        Private slot to generate the requirements specifiers list.
+        """
+        ok = (
+            EricMessageBox.yesNo(
+                self,
+                self.__title,
+                self.tr(
+                    """The requirements were changed. Do you want"""
+                    """ to overwrite these changes?"""
+                ),
+            )
+            if self.__requirementsEdited
+            else True
+        )
+        if ok:
+            self.requirementsEdit.clear()
+            self.__requirementsAvailable = False
+
+            if not bool(self.requirementsFilePicker.text()):
+                self.requirementsFilePicker.setText("requirements.txt")
+
+            fileName = FileSystemUtilities.toNativeSeparators(
+                self.requirementsFilePicker.text()
+            )
+            if fileName and not os.path.isabs(fileName):
+                fileName = ""
+
+            modules = circup.find_modules(self.__devicePath, circup.get_bundles_list())
+            specifiers = []
+            if modules:
+                for module in modules:
+                    specifiers.append(
+                        "{0}=={1}".format(module.name, module.device_version)
+                    )
+
+            if specifiers:
+                self.requirementsEdit.setPlainText("\n".join(specifiers) + "\n")
+                self.__requirementsAvailable = True
+            else:
+                self.requirementsEdit.setPlainText(
+                    self.tr("No package specifiers generated.")
+                )
+
+            self.__updateButtons()
+
+            self.__requirementsEdited = False
+
+    def __writeToFile(self, fileName):
+        """
+        Private method to write the requirements text to a file.
+
+        @param fileName name of the file to write to
+        @type str
+        """
+        if os.path.exists(fileName):
+            ok = EricMessageBox.warning(
+                self,
+                self.__title,
+                self.tr(
+                    """The file <b>{0}</b> already exists. Do you want"""
+                    """ to overwrite it?"""
+                ).format(fileName),
+            )
+            if not ok:
+                return
+
+        txt = self.requirementsEdit.toPlainText()
+        try:
+            with open(fileName, "w") as f:
+                f.write(txt)
+        except OSError as err:
+            EricMessageBox.critical(
+                self,
+                self.__title,
+                self.tr(
+                    """<p>The requirements could not be written"""
+                    """ to <b>{0}</b>.</p><p>Reason: {1}</p>"""
+                ).format(fileName, str(err)),
+            )
+
+    @pyqtSlot()
+    def on_saveButton_clicked(self):
+        """
+        Private slot to save the requirements text to the requirements file.
+        """
+        fileName = self.requirementsFilePicker.text()
+        self.__writeToFile(fileName)
+
+    @pyqtSlot()
+    def on_saveToButton_clicked(self):
+        """
+        Private slot to write the requirements text to a new file.
+        """
+        fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter(
+            self,
+            self.__title,
+            os.path.expanduser("~"),
+            self.tr("Text Files (*.txt);;All Files (*)"),
+            None,
+            EricFileDialog.DontConfirmOverwrite,
+        )
+        if fileName:
+            ext = os.path.splitext(fileName)[1]
+            if not ext:
+                ex = selectedFilter.split("(*")[1].split(")")[0]
+                if ex:
+                    fileName += ex
+            self.__writeToFile(fileName)
+
+    @pyqtSlot()
+    def on_copyButton_clicked(self):
+        """
+        Private slot to copy the requirements text to the clipboard.
+        """
+        txt = self.requirementsEdit.toPlainText()
+        cb = QGuiApplication.clipboard()
+        cb.setText(txt)
+
+    @pyqtSlot()
+    def on_insertButton_clicked(self):
+        """
+        Private slot to insert the requirements text at the cursor position
+        of the current editor.
+        """
+        aw = ericApp().getObject("ViewManager").activeWindow()
+        if aw:
+            aw.beginUndoAction()
+            aw.insert(self.requirementsEdit.toPlainText())
+            aw.endUndoAction()
+
+    @pyqtSlot()
+    def on_replaceSelectionButton_clicked(self):
+        """
+        Private slot to replace the selected text of the current editor
+        with the requirements text.
+        """
+        aw = ericApp().getObject("ViewManager").activeWindow()
+        if aw:
+            aw.beginUndoAction()
+            aw.replaceSelectedText(self.requirementsEdit.toPlainText())
+            aw.endUndoAction()
+
+    @pyqtSlot()
+    def on_replaceAllButton_clicked(self):
+        """
+        Private slot to replace the text of the current editor with the
+        requirements text.
+        """
+        aw = ericApp().getObject("ViewManager").activeWindow()
+        if aw:
+            aw.setText(self.requirementsEdit.toPlainText())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/RequirementsDialog.ui	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RequirementsDialog</class>
+ <widget class="QDialog" name="RequirementsDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>550</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Generate Requirements</string>
+  </property>
+  <property name="toolTip">
+   <string>Replace the current selection with the requirements text</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Requirements File:</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="EricPathPicker" name="requirementsFilePicker" native="true">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::StrongFocus</enum>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="3" column="1">
+      <widget class="Line" name="line">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QPushButton" name="copyButton">
+       <property name="toolTip">
+        <string>Copy the requirements text to the clipboard</string>
+       </property>
+       <property name="text">
+        <string>Copy</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QPushButton" name="saveButton">
+       <property name="toolTip">
+        <string>Press to save to the requirements file</string>
+       </property>
+       <property name="text">
+        <string>Save</string>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="1">
+      <widget class="QPushButton" name="insertButton">
+       <property name="toolTip">
+        <string>Insert the requirements text at the cursor position</string>
+       </property>
+       <property name="text">
+        <string>Insert</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="1">
+      <widget class="QPushButton" name="replaceSelectionButton">
+       <property name="text">
+        <string>Replace Selection</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0" rowspan="9">
+      <widget class="QPlainTextEdit" name="requirementsEdit">
+       <property name="tabChangesFocus">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="1">
+      <widget class="QPushButton" name="replaceAllButton">
+       <property name="toolTip">
+        <string>Replace all text with the requirements text</string>
+       </property>
+       <property name="text">
+        <string>Replace All</string>
+       </property>
+      </widget>
+     </item>
+     <item row="8" column="1">
+      <spacer name="verticalSpacer">
+       <property name="orientation">
+        <enum>Qt::Vertical</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>20</width>
+         <height>40</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item row="1" column="1">
+      <widget class="QPushButton" name="saveToButton">
+       <property name="toolTip">
+        <string>Save to a new file</string>
+       </property>
+       <property name="text">
+        <string>Save To</string>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QLabel" name="label_2">
+       <property name="text">
+        <string>&lt;b&gt;Editor Actions&lt;/b&gt;</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignCenter</set>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>EricPathPicker</class>
+   <extends>QWidget</extends>
+   <header>eric7/EricWidgets/EricPathPicker.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>requirementsFilePicker</tabstop>
+  <tabstop>requirementsEdit</tabstop>
+  <tabstop>saveButton</tabstop>
+  <tabstop>saveToButton</tabstop>
+  <tabstop>copyButton</tabstop>
+  <tabstop>insertButton</tabstop>
+  <tabstop>replaceSelectionButton</tabstop>
+  <tabstop>replaceAllButton</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>RequirementsDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>RequirementsDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowBundlesDialog.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog showing the available bundles and their modules.
+"""
+
+import circup
+
+from PyQt6.QtCore import Qt
+from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
+
+from .Ui_ShowBundlesDialog import Ui_ShowBundlesDialog
+
+
+class ShowBundlesDialog(QDialog, Ui_ShowBundlesDialog):
+    """
+    Class implementing a dialog showing the available bundles and their modules.
+    """
+
+    def __init__(self, withModules, parent=None):
+        """
+        Constructor
+
+        @param withModules flag indicating to list the modules and their version
+        @type bool
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.header.setText(
+            self.tr("Available Bundles and Modules")
+            if withModules
+            else self.tr("Available Bundles")
+        )
+        self.bundlesWidget.setColumnCount(2)
+
+        localBundles = circup.get_bundles_local_dict().values()
+        bundles = circup.get_bundles_list()
+        availableModules = circup.get_bundle_versions(bundles)
+
+        for bundle in bundles:
+            topItm = QTreeWidgetItem(
+                self.bundlesWidget, [bundle.key, bundle.current_tag]
+            )
+            topItm.setExpanded(True)
+            if bundle.key in localBundles:
+                font = topItm.font(0)
+                font.setUnderline(True)
+                topItm.setFont(0, font)
+            itm = QTreeWidgetItem(topItm, [bundle.url])
+            itm.setFirstColumnSpanned(True)
+
+            if withModules:
+                modulesHeader = QTreeWidgetItem(topItm, [self.tr("Modules")])
+                modulesHeader.setExpanded(True)
+                for name, mod in sorted(availableModules.items()):
+                    if mod["bundle"] == bundle:
+                        QTreeWidgetItem(
+                            modulesHeader,
+                            [name, mod.get("__version__", self.tr("unknown"))],
+                        )
+
+        self.bundlesWidget.resizeColumnToContents(0)
+        self.bundlesWidget.resizeColumnToContents(1)
+        self.bundlesWidget.sortItems(0, Qt.SortOrder.AscendingOrder)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowBundlesDialog.ui	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ShowBundlesDialog</class>
+ <widget class="QDialog" name="ShowBundlesDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>700</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>CircuitPython Bundles</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="header">
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="bundlesWidget">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::NoSelection</enum>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="headerHidden">
+      <bool>true</bool>
+     </property>
+     <property name="expandsOnDoubleClick">
+      <bool>false</bool>
+     </property>
+     <column>
+      <property name="text">
+       <string notr="true">1</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ShowBundlesDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ShowBundlesDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowInstalledDialog.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show the modules installed on the connected device.
+"""
+
+import circup
+
+from PyQt6.QtCore import Qt
+from PyQt6.QtWidgets import QDialog, QTreeWidgetItem
+
+from .Ui_ShowInstalledDialog import Ui_ShowInstalledDialog
+
+
+class ShowInstalledDialog(QDialog, Ui_ShowInstalledDialog):
+    """
+    Class implementing a dialog to show the modules installed on the connected device.
+    """
+
+    def __init__(self, devicePath, parent=None):
+        """
+        Constructor
+
+        @param devicePath path to the connected board
+        @type str
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.modulesList.clear()
+        deviceModules = circup.get_device_versions(devicePath)
+        for name, metadata in deviceModules.items():
+            QTreeWidgetItem(
+                self.modulesList,
+                [name, metadata.get("__version__", self.tr("unknown"))],
+            )
+
+        self.modulesList.sortItems(0, Qt.SortOrder.AscendingOrder)
+        self.modulesList.resizeColumnToContents(0)
+        self.modulesList.resizeColumnToContents(1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowInstalledDialog.ui	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ShowInstalledDialog</class>
+ <widget class="QDialog" name="ShowInstalledDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>500</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Installed Modules</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QTreeWidget" name="modulesList">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::NoSelection</enum>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="itemsExpandable">
+      <bool>false</bool>
+     </property>
+     <attribute name="headerShowSortIndicator" stdset="0">
+      <bool>false</bool>
+     </attribute>
+     <column>
+      <property name="text">
+       <string>Module</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Version</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ShowInstalledDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ShowInstalledDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowOutdatedDialog.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,156 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show outdated modules of a connected device.
+"""
+
+import circup
+
+from PyQt6.QtCore import Qt, pyqtSlot
+from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QTreeWidgetItem
+from semver import VersionInfo
+
+from .Ui_ShowOutdatedDialog import Ui_ShowOutdatedDialog
+
+
+class ShowOutdatedDialog(QDialog, Ui_ShowOutdatedDialog):
+    """
+    Class implementing a dialog to show outdated modules of a connected device.
+    """
+
+    def __init__(self, devicePath, selectionMode=False, parent=None):
+        """
+        Constructor
+
+        @param devicePath path to the connected board
+        @type str
+        @param selectionMode flag indicating the activation of the selection mode
+            (defaults to False)
+        @type bool (optional)
+        @param parent reference to the parent widget (defaults to None)
+        @type QWidget (optional)
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.header.clear()
+        self.modulesList.clear()
+
+        self.__checkCount = 0
+        self.__selectionMode = selectionMode
+        if self.__selectionMode:
+            self.buttonBox.setStandardButtons(
+                QDialogButtonBox.StandardButton.Ok
+                | QDialogButtonBox.StandardButton.Cancel
+            )
+        else:
+            self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close)
+
+        self.__modules = {
+            m.name: m
+            for m in circup.find_modules(devicePath, circup.get_bundles_list())
+            if m.outofdate
+        }
+        if self.__modules:
+            self.header.setText(
+                self.tr(
+                    "The following modules are out of date or probably need an update."
+                    "\nMajor Updates may include breaking changes. Review before"
+                    " updating.\nMPY Format changes require an update."
+                )
+            )
+            for module in self.__modules.values():
+                if isinstance(module.bundle_version, str) and not VersionInfo.isvalid(
+                    module.bundle_version
+                ):
+                    reason = self.tr("Incorrect '__version__' Metadata")
+                    needsUpdate = True
+                elif module.bad_format:
+                    reason = self.tr("Corrupted or Unknown MPY Format")
+                    needsUpdate = True
+                elif module.mpy_mismatch:
+                    reason = self.tr("MPY Format")
+                    needsUpdate = True
+                elif module.major_update:
+                    reason = self.tr("Major Version")
+                    needsUpdate = False
+                else:
+                    reason = self.tr("Minor Version")
+                    needsUpdate = False
+                itm = QTreeWidgetItem(
+                    self.modulesList,
+                    [
+                        module.name,
+                        module.device_version
+                        if module.device_version
+                        else self.tr("unknown"),
+                        module.bundle_version
+                        if module.bundle_version
+                        else self.tr("unknown"),
+                        reason,
+                    ],
+                )
+                if self.__selectionMode:
+                    itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable)
+                    itm.setCheckState(
+                        0,
+                        Qt.CheckState.Checked
+                        if needsUpdate
+                        else Qt.CheckState.Unchecked,
+                    )
+                    if needsUpdate:
+                        self.__checkCount += 1
+        else:
+            self.header.setText(self.tr("All modules are up-to-date."))
+
+        self.modulesList.sortItems(0, Qt.SortOrder.AscendingOrder)
+        for column in range(self.modulesList.columnCount()):
+            self.modulesList.resizeColumnToContents(column)
+
+        self.__checkCountUpdated()
+
+    @pyqtSlot(QTreeWidgetItem, int)
+    def on_modulesList_itemChanged(self, item, column):
+        """
+        Private slot to handle a change of the check state of an item.
+
+        @param item reference to the changed item
+        @type QTreeWidgetItem
+        @param column changed column
+        @type int
+        """
+        if self.__selectionMode:
+            if item.checkState(0) == Qt.CheckState.Checked:
+                self.__checkCount += 1
+            else:
+                self.__checkCount -= 1
+
+            self.__checkCountUpdated()
+
+    def __checkCountUpdated(self):
+        """
+        Private method to handle an update of the check count.
+        """
+        if self.__selectionMode:
+            self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(
+                self.__checkCount > 0
+            )
+
+    def getSelection(self):
+        """
+        Public method to get the list of selected modules.
+
+        @return list of selected modules
+        @rtype circup.Module
+        """
+        results = []
+        if self.__selectionMode:
+            for row in range(self.modulesList.topLevelItemCount()):
+                itm = self.modulesList.topLevelItem(row)
+                if itm.checkState(0) == Qt.CheckState.Checked:
+                    results.append(self.__modules[itm.text(0)])
+
+        return results
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/ShowOutdatedDialog.ui	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ShowOutdatedDialog</class>
+ <widget class="QDialog" name="ShowOutdatedDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>500</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Outdated Modules</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QLabel" name="header">
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="modulesList">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionMode">
+      <enum>QAbstractItemView::NoSelection</enum>
+     </property>
+     <property name="rootIsDecorated">
+      <bool>false</bool>
+     </property>
+     <property name="itemsExpandable">
+      <bool>false</bool>
+     </property>
+     <attribute name="headerShowSortIndicator" stdset="0">
+      <bool>false</bool>
+     </attribute>
+     <column>
+      <property name="text">
+       <string>Module</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Version</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Latest</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Update Reason</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>ShowOutdatedDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>ShowOutdatedDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/CircuitPythonUpdater/__init__.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the updater and associated dialogs.
+"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/DeviceBase.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,362 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing some utility functions and the MicroPythonDevice base
+class.
+"""
+
+import contextlib
+import copy
+import os
+
+from PyQt6.QtCore import QObject, pyqtSlot
+from PyQt6.QtWidgets import QInputDialog
+
+from eric7 import Preferences
+from eric7.EricWidgets import EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+
+
+class BaseDevice(QObject):
+    """
+    Base class for the more specific MicroPython devices.
+    """
+
+    def __init__(self, microPythonWidget, deviceType, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(parent)
+
+        self._deviceType = deviceType
+        self.microPython = microPythonWidget
+        self._deviceData = {}  # dictionary with essential device data
+
+    def setConnected(self, connected):
+        """
+        Public method to set the connection state.
+
+        Note: This method can be overwritten to perform actions upon connect
+        or disconnect of the device.
+
+        @param connected connection state
+        @type bool
+        """
+        self._deviceData = {}
+
+        if connected:
+            with contextlib.suppress(OSError):
+                self._deviceData = self.microPython.commandsInterface().getDeviceData()
+
+    def getDeviceType(self):
+        """
+        Public method to get the device type.
+
+        @return type of the device
+        @rtype str
+        """
+        return self._deviceType
+
+    def getDeviceData(self):
+        """
+        Public method to get a copy of the determined device data.
+
+        @return dictionary containing the essential device data
+        @rtype dict
+        """
+        return copy.deepcopy(self._deviceData)
+
+    def checkDeviceData(self):
+        """
+        Public method to check the validity of the device data determined during
+        connecting the device.
+
+        @return flag indicating valid device data
+        @rtype bool
+        """
+        if bool(self._deviceData):
+            return True
+        else:
+            EricMessageBox.critical(
+                None,
+                self.tr("Show MicroPython Versions"),
+                self.tr(
+                    """<p>The device data is not available. Try to connect to the"""
+                    """ device again. Aborting...</p>"""
+                ).format(self.getDeviceType()),
+            )
+            return False
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        self.microPython.setActionButtons(
+            open=False, save=False, run=False, repl=False, files=False, chart=False
+        )
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return True
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.tr("Unsupported Device")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return False, self.tr("REPL is not supported by this device.")
+
+    def setRepl(self, on):
+        """
+        Public method to set the REPL status and dependent status.
+
+        @param on flag indicating the active status
+        @type bool
+        """
+        pass
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return False, self.tr("Plotter is not supported by this device.")
+
+    def setPlotter(self, on):
+        """
+        Public method to set the Plotter status and dependent status.
+
+        @param on flag indicating the active status
+        @type bool
+        """
+        pass
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return False, self.tr("Running scripts is not supported by this device.")
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pass
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return False, self.tr("File Manager is not supported by this device.")
+
+    def setFileManager(self, on):
+        """
+        Public method to set the File Manager status and dependent status.
+
+        @param on flag indicating the active status
+        @type bool
+        """
+        pass
+
+    def supportsLocalFileAccess(self):
+        """
+        Public method to indicate file access via a local directory.
+
+        @return flag indicating file access via local directory
+        @rtype bool
+        """
+        return False  # default
+
+    def getWorkspace(self):
+        """
+        Public method to get the workspace directory.
+
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        return (
+            Preferences.getMicroPython("MpyWorkspace")
+            or Preferences.getMultiProject("Workspace")
+            or os.path.expanduser("~")
+        )
+
+    def selectDeviceDirectory(self, deviceDirectories):
+        """
+        Public method to select the device directory from a list of detected
+        ones.
+
+        @param deviceDirectories list of directories to select from
+        @type list of str
+        @return selected directory or an empty string
+        @rtype str
+        """
+        deviceDirectory, ok = QInputDialog.getItem(
+            None,
+            self.tr("Select Device Directory"),
+            self.tr("Select the directory for the connected device:"),
+            [""] + deviceDirectories,
+            0,
+            False,
+        )
+        if ok:
+            return deviceDirectory
+        else:
+            # user cancelled
+            return ""
+
+    def sendCommands(self, commandsList):
+        """
+        Public method to send a list of commands to the device.
+
+        @param commandsList list of commands to be sent to the device
+        @type list of str
+        """
+        rawOn = [  # sequence of commands to enter raw mode
+            b"\x02",  # Ctrl-B: exit raw repl (just in case)
+            b"\r\x03\x03\x03",  # Ctrl-C three times: interrupt any running
+            # program
+            b"\r\x01",  # Ctrl-A: enter raw REPL
+        ]
+        newLine = [
+            b'print("\\n")\r',
+        ]
+        commands = [c.encode("utf-8)") + b"\r" for c in commandsList]
+        commands.append(b"\r")
+        commands.append(b"\x04")
+        rawOff = [b"\x02", b"\x02"]
+        commandSequence = rawOn + newLine + commands + rawOff
+        self.microPython.commandsInterface().executeAsync(commandSequence)
+
+    @pyqtSlot()
+    def handleDataFlood(self):
+        """
+        Public slot handling a data floof from the device.
+        """
+        pass
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        pass
+
+    def hasFlashMenuEntry(self):
+        """
+        Public method to check, if the device has its own flash menu entry.
+
+        @return flag indicating a specific flash menu entry
+        @rtype bool
+        """
+        return False
+
+    def hasTimeCommands(self):
+        """
+        Public method to check, if the device supports time commands.
+
+        The default returns True.
+
+        @return flag indicating support for time commands
+        @rtype bool
+        """
+        return True
+
+    def hasDocumentationUrl(self):
+        """
+        Public method to check, if the device has a configured documentation
+        URL.
+
+        @return flag indicating a configured documentation URL
+        @rtype bool
+        """
+        return bool(self.getDocumentationUrl())
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        return ""
+
+    def hasFirmwareUrl(self):
+        """
+        Public method to check, if the device has a configured firmware
+        download URL.
+
+        @return flag indicating a configured firmware download URL
+        @rtype bool
+        """
+        return bool(self.getFirmwareUrl())
+
+    def getFirmwareUrl(self):
+        """
+        Public method to get the device firmware download URL.
+
+        @return firmware download URL of the device
+        @rtype str
+        """
+        return ""
+
+    def downloadFirmware(self):
+        """
+        Public method to download the device firmware.
+        """
+        url = self.getFirmwareUrl()
+        if url:
+            ericApp().getObject("UserInterface").launchHelpViewer(url)
+
+    def getDownloadMenuEntries(self):
+        """
+        Public method to retrieve the entries for the downloads menu.
+
+        @return list of tuples with menu text and URL to be opened for each
+            entry
+        @rtype list of tuple of (str, str)
+        """
+        return []
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/EspDevices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,598 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for ESP32 and ESP8266 based
+boards.
+"""
+
+from PyQt6.QtCore import QProcess, QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
+from PyQt6.QtWidgets import QDialog, QMenu
+
+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 . import FirmwareGithubUrls
+from .DeviceBase import BaseDevice
+from ..MicroPythonWidget import HAS_QTCHART
+
+
+class EspDevice(BaseDevice):
+    """
+    Class implementing the device for ESP32 and ESP8266 based boards.
+    """
+
+    def __init__(self, microPythonWidget, deviceType, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__createEsp32Submenu()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return True
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.tr("ESP8266, ESP32")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def __createEsp32Submenu(self):
+        """
+        Private method to create the ESP32 submenu.
+        """
+        self.__espMenu = QMenu(self.tr("ESP32 Functions"))
+
+        self.__showMpyAct = self.__espMenu.addAction(
+            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
+        )
+        self.__espMenu.addSeparator()
+        self.__eraseFlashAct = self.__espMenu.addAction(
+            self.tr("Erase Flash"), self.__eraseFlash
+        )
+        self.__flashMpyAct = self.__espMenu.addAction(
+            self.tr("Flash MicroPython Firmware"), self.__flashMicroPython
+        )
+        self.__espMenu.addSeparator()
+        self.__flashAdditionalAct = self.__espMenu.addAction(
+            self.tr("Flash Additional Firmware"), self.__flashAddons
+        )
+        self.__espMenu.addSeparator()
+        self.__backupAct = self.__espMenu.addAction(
+            self.tr("Backup Firmware"), self.__backupFlash
+        )
+        self.__restoreAct = self.__espMenu.addAction(
+            self.tr("Restore Firmware"), self.__restoreFlash
+        )
+        self.__espMenu.addSeparator()
+        self.__chipIdAct = self.__espMenu.addAction(
+            self.tr("Show Chip ID"), self.__showChipID
+        )
+        self.__flashIdAct = self.__espMenu.addAction(
+            self.tr("Show Flash ID"), self.__showFlashID
+        )
+        self.__macAddressAct = self.__espMenu.addAction(
+            self.tr("Show MAC Address"), self.__showMACAddress
+        )
+        self.__espMenu.addSeparator()
+        self.__resetAct = self.__espMenu.addAction(
+            self.tr("Reset Device"), self.__resetDevice
+        )
+        self.__espMenu.addSeparator()
+        self.__espMenu.addAction(self.tr("Install 'esptool.py'"), self.__installEspTool)
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        connected = self.microPython.isConnected()
+        linkConnected = self.microPython.isLinkConnected()
+
+        self.__showMpyAct.setEnabled(connected)
+        self.__eraseFlashAct.setEnabled(not linkConnected)
+        self.__flashMpyAct.setEnabled(not linkConnected)
+        self.__flashAdditionalAct.setEnabled(not linkConnected)
+        self.__backupAct.setEnabled(not linkConnected)
+        self.__restoreAct.setEnabled(not linkConnected)
+        self.__chipIdAct.setEnabled(not linkConnected)
+        self.__flashIdAct.setEnabled(not linkConnected)
+        self.__macAddressAct.setEnabled(not linkConnected)
+        self.__resetAct.setEnabled(connected or not linkConnected)
+
+        menu.addMenu(self.__espMenu)
+
+    def hasFlashMenuEntry(self):
+        """
+        Public method to check, if the device has its own flash menu entry.
+
+        @return flag indicating a specific flash menu entry
+        @rtype bool
+        """
+        return True
+
+    @pyqtSlot()
+    def __eraseFlash(self):
+        """
+        Private slot to erase the device flash memory.
+        """
+        ok = EricMessageBox.yesNo(
+            self.microPython,
+            self.tr("Erase Flash"),
+            self.tr("""Shall the flash of the selected device really be erased?"""),
+        )
+        if ok:
+            flashArgs = [
+                "-u",
+                "-m",
+                "esptool",
+                "--port",
+                self.microPython.getCurrentPort(),
+                "erase_flash",
+            ]
+            dlg = EricProcessDialog(
+                self.tr("'esptool erase_flash' Output"),
+                self.tr("Erase Flash"),
+                showProgress=True,
+            )
+            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
+            if res:
+                dlg.exec()
+
+    @pyqtSlot()
+    def __flashMicroPython(self):
+        """
+        Private slot to flash a MicroPython firmware to the device.
+        """
+        from .EspDialogs.EspFirmwareSelectionDialog import EspFirmwareSelectionDialog
+
+        dlg = EspFirmwareSelectionDialog()
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            chip, firmware, baudRate, flashMode, flashAddress = dlg.getData()
+            flashArgs = [
+                "-u",
+                "-m",
+                "esptool",
+                "--chip",
+                chip,
+                "--port",
+                self.microPython.getCurrentPort(),
+            ]
+            if baudRate != "115200":
+                flashArgs += ["--baud", baudRate]
+            flashArgs.append("write_flash")
+            if flashMode:
+                flashArgs += ["--flash_mode", flashMode]
+            flashArgs += [
+                flashAddress,
+                firmware,
+            ]
+            dlg = EricProcessDialog(
+                self.tr("'esptool write_flash' Output"),
+                self.tr("Flash MicroPython Firmware"),
+                showProgress=True,
+            )
+            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
+            if res:
+                dlg.exec()
+
+    @pyqtSlot()
+    def __flashAddons(self):
+        """
+        Private slot to flash some additional firmware images.
+        """
+        from .EspDialogs.EspFirmwareSelectionDialog import EspFirmwareSelectionDialog
+
+        dlg = EspFirmwareSelectionDialog(addon=True)
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            chip, firmware, baudRate, flashMode, flashAddress = dlg.getData()
+            flashArgs = [
+                "-u",
+                "-m",
+                "esptool",
+                "--chip",
+                chip,
+                "--port",
+                self.microPython.getCurrentPort(),
+            ]
+            if baudRate != "115200":
+                flashArgs += ["--baud", baudRate]
+            flashArgs.append("write_flash")
+            if flashMode:
+                flashArgs += ["--flash_mode", flashMode]
+            flashArgs += [
+                flashAddress.lower(),
+                firmware,
+            ]
+            dlg = EricProcessDialog(
+                self.tr("'esptool write_flash' Output"),
+                self.tr("Flash Additional Firmware"),
+                showProgress=True,
+            )
+            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
+            if res:
+                dlg.exec()
+
+    @pyqtSlot()
+    def __backupFlash(self):
+        """
+        Private slot to backup the currently flashed firmware.
+        """
+        from .EspDialogs.EspBackupRestoreFirmwareDialog import (
+            EspBackupRestoreFirmwareDialog
+        )
+
+        dlg = EspBackupRestoreFirmwareDialog(backupMode=True)
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            chip, flashSize, baudRate, flashMode, firmware = dlg.getData()
+            flashArgs = [
+                "-u",
+                "-m",
+                "esptool",
+                "--chip",
+                chip,
+                "--port",
+                self.microPython.getCurrentPort(),
+                "--baud",
+                baudRate,
+                "read_flash",
+                "0x0",
+                flashSize,
+                firmware,
+            ]
+            dlg = EricProcessDialog(
+                self.tr("'esptool read_flash' Output"),
+                self.tr("Backup Firmware"),
+                showProgress=True,
+            )
+            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
+            if res:
+                dlg.exec()
+
+    @pyqtSlot()
+    def __restoreFlash(self):
+        """
+        Private slot to restore a previously saved firmware.
+        """
+        from .EspDialogs.EspBackupRestoreFirmwareDialog import (
+            EspBackupRestoreFirmwareDialog
+        )
+
+        dlg = EspBackupRestoreFirmwareDialog(backupMode=False)
+        if dlg.exec() == QDialog.DialogCode.Accepted:
+            chip, flashSize, baudRate, flashMode, firmware = dlg.getData()
+            flashArgs = [
+                "-u",
+                "-m",
+                "esptool",
+                "--chip",
+                chip,
+                "--port",
+                self.microPython.getCurrentPort(),
+                "--baud",
+                baudRate,
+                "write_flash",
+            ]
+            if flashMode:
+                flashArgs.extend(
+                    [
+                        "--flash_mode",
+                        flashMode,
+                    ]
+                )
+            if bool(flashSize):
+                flashArgs.extend(
+                    [
+                        "--flash_size",
+                        flashSize,
+                    ]
+                )
+            flashArgs.extend(
+                [
+                    "0x0",
+                    firmware,
+                ]
+            )
+            dlg = EricProcessDialog(
+                self.tr("'esptool write_flash' Output"),
+                self.tr("Restore Firmware"),
+                showProgress=True,
+            )
+            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
+            if res:
+                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():
+            if self._deviceData["mpy_name"] == "micropython":
+                url = QUrl(FirmwareGithubUrls["micropython"])
+            elif self._deviceData["mpy_name"] == "circuitpython":
+                url = QUrl(FirmwareGithubUrls["circuitpython"])
+            else:
+                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"""
+                        """ or CircuitPython. Aborting..."""
+                    ),
+                )
+                return
+
+            ui = ericApp().getObject("UserInterface")
+            request = QNetworkRequest(url)
+            reply = ui.networkAccessManager().head(request)
+            reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
+
+    def __firmwareVersionResponse(self, reply):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        """
+        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 self._deviceData["mpy_version"] == "unknown":
+            currentVersionStr = self.tr("unknown")
+            currentVersion = (0, 0, 0)
+        else:
+            currentVersionStr = self._deviceData["mpy_version"]
+            currentVersion = Globals.versionToTuple(currentVersionStr)
+
+        if self._deviceData["mpy_name"] == "circuitpython":
+            kind = "CircuitPython"
+        elif self._deviceData["mpy_name"] == "micropython":
+            kind = "MicroPython"
+
+        msg = self.tr(
+            "<h4>{0} Version Information</h4>"
+            "<table>"
+            "<tr><td>Installed:</td><td>{1}</td></tr>"
+            "<tr><td>Available:</td><td>{2}</td></tr>"
+            "</table>"
+        ).format(kind, currentVersionStr, tag)
+        if currentVersion < latestVersion:
+            msg += self.tr("<p><b>Update available!</b></p>")
+
+        EricMessageBox.information(
+            None,
+            self.tr("{0} Version").format(kind),
+            msg,
+        )
+
+    @pyqtSlot()
+    def __showChipID(self):
+        """
+        Private slot to show the ID of the ESP chip.
+        """
+        args = [
+            "-u",
+            "-m",
+            "esptool",
+            "--port",
+            self.microPython.getCurrentPort(),
+            "chip_id",
+        ]
+        dlg = EricProcessDialog(
+            self.tr("'esptool chip_id' Output"), self.tr("Show Chip ID")
+        )
+        res = dlg.startProcess(PythonUtilities.getPythonExecutable(), args)
+        if res:
+            dlg.exec()
+
+    @pyqtSlot()
+    def __showFlashID(self):
+        """
+        Private slot to show the ID of the ESP flash chip.
+        """
+        args = [
+            "-u",
+            "-m",
+            "esptool",
+            "--port",
+            self.microPython.getCurrentPort(),
+            "flash_id",
+        ]
+        dlg = EricProcessDialog(
+            self.tr("'esptool flash_id' Output"), self.tr("Show Flash ID")
+        )
+        res = dlg.startProcess(PythonUtilities.getPythonExecutable(), args)
+        if res:
+            dlg.exec()
+
+    @pyqtSlot()
+    def __showMACAddress(self):
+        """
+        Private slot to show the MAC address of the ESP chip.
+        """
+        args = [
+            "-u",
+            "-m",
+            "esptool",
+            "--port",
+            self.microPython.getCurrentPort(),
+            "read_mac",
+        ]
+        dlg = EricProcessDialog(
+            self.tr("'esptool read_mac' Output"), self.tr("Show MAC Address")
+        )
+        res = dlg.startProcess(PythonUtilities.getPythonExecutable(), args)
+        if res:
+            dlg.exec()
+
+    @pyqtSlot()
+    def __resetDevice(self):
+        """
+        Private slot to reset the connected device.
+        """
+        if self.microPython.isConnected():
+            self.microPython.commandsInterface().execute(
+                [
+                    "import machine",
+                    "machine.reset()",
+                ]
+            )
+        else:
+            # perform a reset via esptool using flash_id command ignoring
+            # the output
+            args = [
+                "-u",
+                "-m",
+                "esptool",
+                "--port",
+                self.microPython.getCurrentPort(),
+                "flash_id",
+            ]
+            proc = QProcess()
+            proc.start(PythonUtilities.getPythonExecutable(), args)
+            procStarted = proc.waitForStarted(10000)
+            if procStarted:
+                proc.waitForFinished(10000)
+
+    @pyqtSlot()
+    def __installEspTool(self):
+        """
+        Private slot to install the esptool package via pip.
+        """
+        pip = ericApp().getObject("Pip")
+        pip.installPackages(
+            ["esptool"], interpreter=PythonUtilities.getPythonExecutable()
+        )
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonDocuUrl")
+
+    def getFirmwareUrl(self):
+        """
+        Public method to get the device firmware download URL.
+
+        @return firmware download URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonFirmwareUrl")
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype EspDevice
+    """
+    return EspDevice(microPythonWidget, deviceType)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/EspDialogs/EspBackupRestoreFirmwareDialog.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,198 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to select the ESP chip type and the backup and
+restore parameters.
+"""
+
+import os
+
+from PyQt6.QtCore import pyqtSlot
+from PyQt6.QtWidgets import QDialog, QDialogButtonBox
+
+from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
+
+from .Ui_EspBackupRestoreFirmwareDialog import Ui_EspBackupRestoreFirmwareDialog
+
+
+class EspBackupRestoreFirmwareDialog(QDialog, Ui_EspBackupRestoreFirmwareDialog):
+    """
+    Class implementing a dialog to select the ESP chip type and the backup and
+    restore parameters.
+    """
+
+    Chips = (
+        ("", ""),
+        ("ESP32", "esp32"),
+        ("ESP32-C3", "esp32c3"),
+        ("ESP32-S2", "esp32s2"),
+        ("ESP32-S3", "esp32s3"),
+        ("ESP8266", "esp8266"),
+    )
+
+    FlashModes = [
+        ("", ""),
+        ("Quad I/O", "qio"),
+        ("Quad Output", "qout"),
+        ("Dual I/O", "dio"),
+        ("Dual Output", "dout"),
+    ]
+
+    FlashSizes = {
+        "esp32": [
+            (" 1 MB", "0x100000"),
+            (" 2 MB", "0x200000"),
+            (" 4 MB", "0x400000"),
+            (" 8 MB", "0x800000"),
+            ("16 MB", "0x1000000"),
+        ],
+        "esp32c3": [
+            (" 1 MB", "0x100000"),
+            (" 2 MB", "0x200000"),
+            (" 4 MB", "0x400000"),
+            (" 8 MB", "0x800000"),
+            ("16 MB", "0x1000000"),
+        ],
+        "esp32s2": [
+            (" 1 MB", "0x100000"),
+            (" 2 MB", "0x200000"),
+            (" 4 MB", "0x400000"),
+            (" 8 MB", "0x800000"),
+            ("16 MB", "0x1000000"),
+        ],
+        "esp32s3": [
+            (" 1 MB", "0x100000"),
+            (" 2 MB", "0x200000"),
+            (" 4 MB", "0x400000"),
+            (" 8 MB", "0x800000"),
+            ("16 MB", "0x1000000"),
+        ],
+        "esp8266": [
+            ("256 KB", "0x40000"),
+            ("512 KB", "0x80000"),
+            (" 1 MB", "0x100000"),
+            (" 2 MB", "0x200000"),
+            (" 4 MB", "0x400000"),
+            (" 8 MB", "0x800000"),
+            ("16 MB", "0x1000000"),
+        ],
+    }
+
+    def __init__(self, backupMode=True, parent=None):
+        """
+        Constructor
+
+        @param backupMode flag indicating parameters for a firmware backup are
+            requested
+        @type bool
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.__isBackupMode = backupMode
+
+        for text, chip in self.Chips:
+            self.espComboBox.addItem(text, chip)
+
+        self.baudRateComboBox.addItems(
+            ["74.880", "115.200", "230.400", "460.800", "921.600", "1.500.000"]
+        )
+        self.baudRateComboBox.setCurrentIndex(3)
+
+        self.firmwarePicker.setFilters(self.tr("Firmware Files (*.img);;All Files (*)"))
+        if self.__isBackupMode:
+            self.firmwarePicker.setMode(
+                EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE
+            )
+            self.sizeInfoLabel.clear()
+            self.modeComboBox.setEnabled(False)
+            self.modeInfoLabel.setEnabled(False)
+            self.setWindowTitle(self.tr("Backup Firmware"))
+        else:
+            self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
+            for text, mode in self.FlashModes:
+                self.modeComboBox.addItem(text, mode)
+            self.setWindowTitle(self.tr("Restore Firmware"))
+
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+
+    def __updateOkButton(self):
+        """
+        Private method to update the state of the OK button.
+        """
+        firmwareFile = self.firmwarePicker.text()
+        enable = bool(self.espComboBox.currentText()) and bool(firmwareFile)
+        if self.__isBackupMode:
+            enable &= bool(self.sizeComboBox.currentText())
+        else:
+            enable &= os.path.exists(firmwareFile)
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable)
+
+    @pyqtSlot(str)
+    def on_espComboBox_currentTextChanged(self, chip):
+        """
+        Private slot to handle the selection of a chip type.
+
+        @param chip selected chip type
+        @type str
+        """
+        selectedSize = self.sizeComboBox.currentText()
+        self.sizeComboBox.clear()
+        chipType = self.espComboBox.currentData()
+        if chipType and chipType in self.FlashSizes:
+            self.sizeComboBox.addItem("")
+            for text, data in self.FlashSizes[chipType]:
+                self.sizeComboBox.addItem(text, data)
+
+            self.sizeComboBox.setCurrentText(selectedSize)
+
+        self.__updateOkButton()
+
+    @pyqtSlot(str)
+    def on_sizeComboBox_currentTextChanged(self, size):
+        """
+        Private slot handling a change of the selected firmware size.
+
+        @param size selected size text
+        @type str
+        """
+        self.__updateOkButton()
+
+    @pyqtSlot(str)
+    def on_firmwarePicker_textChanged(self, firmware):
+        """
+        Private slot handling a change of the firmware path.
+
+        @param firmware path to the firmware
+        @type str
+        """
+        self.__updateOkButton()
+
+    def getData(self):
+        """
+        Public method to get the entered data.
+
+        @return tuple containing the selected chip type, the firmware size,
+            the baud rate or flashing, the flash mode and the path of the
+            firmware file
+        @rtype tuple of (str, str, str, str, str)
+        """
+        flashSize = (
+            self.sizeComboBox.currentData()
+            if self.__isBackupMode
+            else self.sizeComboBox.currentText().replace(" ", "")
+        )
+
+        return (
+            self.espComboBox.currentData(),
+            flashSize,
+            self.baudRateComboBox.currentText().replace(".", ""),
+            self.modeComboBox.currentData(),
+            self.firmwarePicker.text(),
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/EspDialogs/EspFirmwareSelectionDialog.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,165 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to select the ESP chip type and the firmware to
+be flashed.
+"""
+
+import os
+
+from PyQt6.QtCore import QRegularExpression, pyqtSlot
+from PyQt6.QtGui import QRegularExpressionValidator
+from PyQt6.QtWidgets import QDialog, QDialogButtonBox
+
+from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
+
+from .Ui_EspFirmwareSelectionDialog import Ui_EspFirmwareSelectionDialog
+
+
+class EspFirmwareSelectionDialog(QDialog, Ui_EspFirmwareSelectionDialog):
+    """
+    Class implementing a dialog to select the ESP chip type and the firmware to
+    be flashed.
+    """
+
+    Chips = (
+        ("", ""),
+        ("ESP32", "esp32"),
+        ("ESP32-C3", "esp32c3"),
+        ("ESP32-S2", "esp32s2"),
+        ("ESP32-S3", "esp32s3"),
+        ("ESP8266", "esp8266"),
+    )
+
+    FlashModes = (
+        ("", ""),
+        ("Quad I/O", "qio"),
+        ("Quad Output", "qout"),
+        ("Dual I/O", "dio"),
+        ("Dual Output", "dout"),
+    )
+
+    FlashAddresses = {
+        "esp8266": "0x0000",
+        "esp32": "0x1000",
+        "esp32c3": "0x0000",
+        "esp32s2": "0x1000",
+        "esp32s3": "0x0000",
+    }
+
+    def __init__(self, addon=False, parent=None):
+        """
+        Constructor
+
+        @param addon flag indicating an addon firmware
+        @type bool
+        @param parent reference to the parent widget
+        @type QWidget
+        """
+        super().__init__(parent)
+        self.setupUi(self)
+
+        self.__addon = addon
+
+        self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
+        self.firmwarePicker.setFilters(self.tr("Firmware Files (*.bin);;All Files (*)"))
+
+        for text, chip in self.Chips:
+            self.espComboBox.addItem(text, chip)
+
+        self.baudRateComboBox.addItems(
+            ["74.880", "115.200", "230.400", "460.800", "921.600", "1.500.000"]
+        )
+        self.baudRateComboBox.setCurrentIndex(3)
+
+        for text, mode in self.FlashModes:
+            self.modeComboBox.addItem(text, mode)
+
+        if addon:
+            self.__validator = QRegularExpressionValidator(
+                QRegularExpression(r"[0-9a-fA-F]{0,7}")
+            )
+            self.addressEdit.setValidator(self.__validator)
+        else:
+            self.addressLabel.hide()
+            self.addressEdit.hide()
+
+        msh = self.minimumSizeHint()
+        self.resize(max(self.width(), msh.width()), msh.height())
+
+    def __updateOkButton(self):
+        """
+        Private method to update the state of the OK button.
+        """
+        firmwareFile = self.firmwarePicker.text()
+        enable = (
+            bool(self.espComboBox.currentText())
+            and bool(firmwareFile)
+            and os.path.exists(firmwareFile)
+        )
+        if self.__addon:
+            enable &= bool(self.addressEdit.text())
+        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable)
+
+    @pyqtSlot(str)
+    def on_espComboBox_currentTextChanged(self, chip):
+        """
+        Private slot to handle the selection of a chip type.
+
+        @param chip selected chip type
+        @type str
+        """
+        self.__updateOkButton()
+
+        self.cpyCheckBox.setEnabled(chip == "ESP32-S2")
+        # possible address override needed for CircuitPython
+
+    @pyqtSlot(str)
+    def on_firmwarePicker_textChanged(self, firmware):
+        """
+        Private slot handling a change of the firmware path.
+
+        @param firmware path to the firmware
+        @type str
+        """
+        self.__updateOkButton()
+
+        self.cpyCheckBox.setChecked("circuitpython" in firmware)
+        # possible address override needed for CircuitPython
+
+    @pyqtSlot(str)
+    def on_addressEdit_textChanged(self, address):
+        """
+        Private slot handling a change of the address.
+
+        @param address entered address
+        @type str
+        """
+        self.__updateOkButton()
+
+    def getData(self):
+        """
+        Public method to get the entered data.
+
+        @return tuple containing the selected chip type, the path of the
+            firmware file, the baud rate, the flash mode and the flash
+            address
+        @rtype tuple of (str, str, str, str, str)
+        """
+        chip = self.espComboBox.currentData()
+
+        address = self.addressEdit.text() if self.__addon else self.FlashAddresses[chip]
+        if not self.__addon and chip == "esp32s2" and self.cpyCheckBox.isChecked():
+            # override address
+            address = "0x0000"
+
+        return (
+            chip,
+            self.firmwarePicker.text(),
+            self.baudRateComboBox.currentText().replace(".", ""),
+            self.modeComboBox.currentData(),
+            address,
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/EspDialogs/__init__.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing dialogs used by the EspDevices module.
+"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/GenericMicroPythonDevices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,227 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for generic MicroPython devices
+(i.e. those devices not specifically supported yet).
+"""
+
+import os
+
+from eric7 import Preferences
+from eric7.EricWidgets import EricMessageBox
+from eric7.SystemUtilities import FileSystemUtilities
+
+from .DeviceBase import BaseDevice
+from .MicroPythonWidget import HAS_QTCHART
+
+
+class GenericMicroPythonDevice(BaseDevice):
+    """
+    Class implementing the device interface for generic MicroPython boards.
+    """
+
+    def __init__(self, microPythonWidget, deviceType, vid, pid, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param vid vendor ID
+        @type int
+        @param pid product ID
+        @type int
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__directAccess = False
+        self.__deviceVolumeName = ""
+        self.__workspace = ""
+        self.__deviceName = ""
+
+        for deviceData in Preferences.getMicroPython("ManualDevices"):
+            if deviceData["vid"] == vid and deviceData["pid"] == pid:
+                self.__deviceVolumeName = deviceData["data_volume"]
+                self.__directAccess = bool(deviceData["data_volume"])
+                self.__deviceName = deviceData["description"]
+
+                if self.__directAccess:
+                    self.__workspace = self.__findWorkspace()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+        if self.__directAccess and self.__deviceVolumeMounted():
+            self.microPython.setActionButtons(open=True, save=True)
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.__deviceName
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def supportsLocalFileAccess(self):
+        """
+        Public method to indicate file access via a local directory.
+
+        @return flag indicating file access via local directory
+        @rtype bool
+        """
+        return self.__deviceVolumeMounted()
+
+    def __deviceVolumeMounted(self):
+        """
+        Private method to check, if the device volume is mounted.
+
+        @return flag indicated a mounted device
+        @rtype bool
+        """
+        if self.__workspace and not os.path.exists(self.__workspace):
+            self.__workspace = ""  # reset
+
+        return self.__directAccess and self.__deviceVolumeName in self.getWorkspace(
+            silent=True
+        )
+
+    def getWorkspace(self, silent=False):
+        """
+        Public method to get the workspace directory.
+
+        @param silent flag indicating silent operations
+        @type bool
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        if self.__directAccess:
+            if self.__workspace:
+                # return cached entry
+                return self.__workspace
+            else:
+                self.__workspace = self.__findWorkspace(silent=silent)
+                return self.__workspace
+        else:
+            return super().getWorkspace()
+
+    def __findWorkspace(self, silent=False):
+        """
+        Private method to find the workspace directory.
+
+        @param silent flag indicating silent operations
+        @type bool
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        # Attempts to find the path on the filesystem that represents the
+        # plugged in board.
+        deviceDirectories = FileSystemUtilities.findVolume(
+            self.__deviceVolumeName, findAll=True
+        )
+
+        if deviceDirectories:
+            if len(deviceDirectories) == 1:
+                return deviceDirectories[0]
+            else:
+                return self.selectDeviceDirectory(deviceDirectories)
+        else:
+            # return the default workspace and give the user a warning (unless
+            # silent mode is selected)
+            if not silent:
+                EricMessageBox.warning(
+                    self.microPython,
+                    self.tr("Workspace Directory"),
+                    self.tr(
+                        "Python files for this generic board can be"
+                        " edited in place, if the device volume is locally"
+                        " available. A volume named '{0}' was not found."
+                        " In place editing will not be available."
+                    ).format(self.__deviceVolumeName),
+                )
+
+            return super().getWorkspace()
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype GenericMicroPythonDevice
+    """
+    return GenericMicroPythonDevice(microPythonWidget, deviceType, vid, pid)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/MicrobitDevices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,654 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for BBC micro:bit and
+Calliope mini boards.
+"""
+
+import contextlib
+import os
+import shutil
+
+from PyQt6.QtCore import QStandardPaths, QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
+from PyQt6.QtWidgets import QInputDialog, QLineEdit, QMenu
+
+from eric7 import Globals, Preferences
+from eric7.EricWidgets import EricFileDialog, EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+from eric7.SystemUtilities import FileSystemUtilities
+
+from . import FirmwareGithubUrls
+from .DeviceBase import BaseDevice
+from ..MicroPythonWidget import HAS_QTCHART
+
+
+class MicrobitDevice(BaseDevice):
+    """
+    Class implementing the device for BBC micro:bit and Calliope mini boards.
+    """
+
+    def __init__(self, microPythonWidget, deviceType, serialNumber, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType type of the device
+        @type str
+        @param serialNumber serial number of the board
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__boardId = 0  # illegal ID
+        if serialNumber:
+            with contextlib.suppress(ValueError):
+                self.__boardId = int(serialNumber[:4], 16)
+
+        self.__createMicrobitMenu()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return True
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        if self.getDeviceType() == "bbc_microbit":
+            # BBC micro:bit
+            return self.tr("BBC micro:bit")
+        else:
+            # Calliope mini
+            return self.tr("Calliope mini")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def hasTimeCommands(self):
+        """
+        Public method to check, if the device supports time commands.
+
+        The default returns True.
+
+        @return flag indicating support for time commands
+        @rtype bool
+        """
+        if (
+            self.microPython.isConnected()
+            and self.checkDeviceData()
+            and self._deviceData["mpy_name"] == "circuitpython"
+        ):
+            return True
+
+        return False
+
+    def __isMicroBitV1(self):
+        """
+        Private method to check, if the device is a BBC micro:bit v1.
+
+        @return falg indicating a BBC micro:bit v1
+        @rtype bool
+        """
+        return self.__boardId in (0x9900, 0x9901)
+
+    def __isMicroBitV2(self):
+        """
+        Private method to check, if the device is a BBC micro:bit v2.
+
+        @return falg indicating a BBC micro:bit v2
+        @rtype bool
+        """
+        return self.__boardId in (0x9903, 0x9904, 0x9905, 0x9906)
+
+    def __isCalliope(self):
+        """
+        Private method to check, if the device is a Calliope mini.
+
+        @return flag indicating a Calliope mini
+        @rtype bool
+        """
+        return self.__boardId in (0x12A0,)
+
+    def __createMicrobitMenu(self):
+        """
+        Private method to create the microbit submenu.
+        """
+        self.__microbitMenu = QMenu(self.tr("BBC micro:bit/Calliope Functions"))
+
+        self.__showMpyAct = self.__microbitMenu.addAction(
+            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
+        )
+        self.__microbitMenu.addSeparator()
+        self.__flashMpyAct = self.__microbitMenu.addAction(
+            self.tr("Flash MicroPython"), self.__flashMicroPython
+        )
+        self.__flashDAPLinkAct = self.__microbitMenu.addAction(
+            self.tr("Flash Firmware"), lambda: self.__flashMicroPython(firmware=True)
+        )
+        self.__microbitMenu.addSeparator()
+        self.__saveScripAct = self.__microbitMenu.addAction(
+            self.tr("Save Script"), self.__saveScriptToDevice
+        )
+        self.__saveScripAct.setToolTip(
+            self.tr("Save the current script to the selected device")
+        )
+        self.__saveMainScriptAct = self.__microbitMenu.addAction(
+            self.tr("Save Script as 'main.py'"), self.__saveMain
+        )
+        self.__saveMainScriptAct.setToolTip(
+            self.tr("Save the current script as 'main.py' on the connected device")
+        )
+        self.__microbitMenu.addSeparator()
+        self.__resetAct = self.__microbitMenu.addAction(
+            self.tr("Reset {0}").format(self.deviceName()), self.__resetDevice
+        )
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        connected = self.microPython.isConnected()
+        linkConnected = self.microPython.isLinkConnected()
+
+        self.__showMpyAct.setEnabled(connected and self.getDeviceType() != "calliope")
+        self.__flashMpyAct.setEnabled(not linkConnected)
+        self.__flashDAPLinkAct.setEnabled(not linkConnected)
+        self.__saveScripAct.setEnabled(connected)
+        self.__saveMainScriptAct.setEnabled(connected)
+        self.__resetAct.setEnabled(connected)
+
+        menu.addMenu(self.__microbitMenu)
+
+    def hasFlashMenuEntry(self):
+        """
+        Public method to check, if the device has its own flash menu entry.
+
+        @return flag indicating a specific flash menu entry
+        @rtype bool
+        """
+        return True
+
+    @pyqtSlot()
+    def __flashMicroPython(self, firmware=False):
+        """
+        Private slot to flash MicroPython or the DAPLink firmware to the
+        device.
+
+        @param firmware flag indicating to flash the DAPLink firmware
+        @type bool
+        """
+        # Attempts to find the path on the file system that represents the
+        # plugged in micro:bit board. To flash the DAPLink firmware, it must be
+        # in maintenance mode, for MicroPython in standard mode.
+        if self.getDeviceType() == "bbc_microbit":
+            # BBC micro:bit
+            if firmware:
+                deviceDirectories = FileSystemUtilities.findVolume(
+                    "MAINTENANCE", findAll=True
+                )
+            else:
+                deviceDirectories = FileSystemUtilities.findVolume(
+                    "MICROBIT", findAll=True
+                )
+        else:
+            # Calliope mini
+            if firmware:
+                deviceDirectories = FileSystemUtilities.findVolume(
+                    "MAINTENANCE", findAll=True
+                )
+            else:
+                deviceDirectories = FileSystemUtilities.findVolume("MINI", findAll=True)
+        if len(deviceDirectories) == 0:
+            if self.getDeviceType() == "bbc_microbit":
+                # BBC micro:bit is not ready or not mounted
+                if firmware:
+                    EricMessageBox.critical(
+                        self.microPython,
+                        self.tr("Flash MicroPython/Firmware"),
+                        self.tr(
+                            "<p>The BBC micro:bit is not ready for flashing"
+                            " the DAPLink firmware. Follow these"
+                            " instructions. </p>"
+                            "<ul>"
+                            "<li>unplug USB cable and any batteries</li>"
+                            "<li>keep RESET button pressed and plug USB cable"
+                            " back in</li>"
+                            "<li>a drive called MAINTENANCE should be"
+                            " available</li>"
+                            "</ul>"
+                            "<p>See the "
+                            '<a href="https://microbit.org/guide/firmware/">'
+                            "micro:bit web site</a> for details.</p>"
+                        ),
+                    )
+                else:
+                    EricMessageBox.critical(
+                        self.microPython,
+                        self.tr("Flash MicroPython/Firmware"),
+                        self.tr(
+                            "<p>The BBC micro:bit is not ready for flashing"
+                            " the MicroPython firmware. Please make sure,"
+                            " that a drive called MICROBIT is available."
+                            "</p>"
+                        ),
+                    )
+            else:
+                # Calliope mini is not ready or not mounted
+                if firmware:
+                    EricMessageBox.critical(
+                        self.microPython,
+                        self.tr("Flash MicroPython/Firmware"),
+                        self.tr(
+                            '<p>The "Calliope mini" is not ready for flashing'
+                            " the DAPLink firmware. Follow these"
+                            " instructions. </p>"
+                            "<ul>"
+                            "<li>unplug USB cable and any batteries</li>"
+                            "<li>keep RESET button pressed an plug USB cable"
+                            " back in</li>"
+                            "<li>a drive called MAINTENANCE should be"
+                            " available</li>"
+                            "</ul>"
+                        ),
+                    )
+                else:
+                    EricMessageBox.critical(
+                        self.microPython,
+                        self.tr("Flash MicroPython/Firmware"),
+                        self.tr(
+                            '<p>The "Calliope mini" is not ready for flashing'
+                            " the MicroPython firmware. Please make sure,"
+                            " that a drive called MINI is available."
+                            "</p>"
+                        ),
+                    )
+        elif len(deviceDirectories) == 1:
+            downloadsPath = QStandardPaths.standardLocations(
+                QStandardPaths.StandardLocation.DownloadLocation
+            )[0]
+            firmware = EricFileDialog.getOpenFileName(
+                self.microPython,
+                self.tr("Flash MicroPython/Firmware"),
+                downloadsPath,
+                self.tr("MicroPython/Firmware Files (*.hex *.bin);;All Files (*)"),
+            )
+            if firmware and os.path.exists(firmware):
+                shutil.copy2(firmware, deviceDirectories[0])
+        else:
+            EricMessageBox.warning(
+                self,
+                self.tr("Flash MicroPython/Firmware"),
+                self.tr(
+                    "There are multiple devices ready for flashing."
+                    " Please make sure, that only one device is prepared."
+                ),
+            )
+
+    @pyqtSlot()
+    def __showFirmwareVersions(self):
+        """
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+        """
+        if self.microPython.isConnected() and self.checkDeviceData():
+            if self._deviceData["mpy_name"] not in ("micropython", "circuitpython"):
+                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"""
+                        """ or CircuitPython. Aborting..."""
+                    ),
+                )
+            else:
+                if self.getDeviceType() == "bbc_microbit":
+                    if self._deviceData["mpy_name"] == "micropython":
+                        if self.__isMicroBitV1():
+                            url = QUrl(FirmwareGithubUrls["microbit_v1"])
+                        elif self.__isMicroBitV2():
+                            url = QUrl(FirmwareGithubUrls["microbit_v2"])
+                        else:
+                            EricMessageBox.critical(
+                                None,
+                                self.tr("Show MicroPython Versions"),
+                                self.tr(
+                                    """<p>The BBC micro:bit generation cannot be"""
+                                    """ determined. Aborting...</p>"""
+                                ),
+                            )
+                            return
+                    elif self._deviceData["mpy_name"] == "circuitpython":
+                        url = QUrl(FirmwareGithubUrls["circuitpython"])
+                else:
+                    EricMessageBox.critical(
+                        None,
+                        self.tr("Show MicroPython Versions"),
+                        self.tr(
+                            """<p>The firmware URL for the device type <b>{0}</b>"""
+                            """ is not known. Aborting...</p>"""
+                        ).format(self.getDeviceType()),
+                    )
+                    return
+
+                ui = ericApp().getObject("UserInterface")
+                request = QNetworkRequest(url)
+                reply = ui.networkAccessManager().head(request)
+                reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
+
+    def __firmwareVersionResponse(self, reply):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        """
+        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 self._deviceData["release"] == "unknown":
+            currentVersionStr = self.tr("unknown")
+            currentVersion = (0, 0, 0)
+        else:
+            currentVersionStr = self._deviceData["release"]
+            currentVersion = Globals.versionToTuple(currentVersionStr)
+
+        if self._deviceData["mpy_name"] == "circuitpython":
+            kind = "CircuitPython"
+            microbitVersion = "2"  # only v2 device can run CircuitPython
+        elif self._deviceData["mpy_name"] == "micropython":
+            kind = "MicroPython"
+            if self.__isMicroBitV1():
+                microbitVersion = "1"
+            elif self.__isMicroBitV2():
+                microbitVersion = "2"
+        else:
+            kind = self.tr("Firmware")
+            microbitVersion = "?"
+
+        msg = self.tr(
+            "<h4>{0} Version Information<br/>"
+            "(BBC micro:bit v{1})</h4>"
+            "<table>"
+            "<tr><td>Installed:</td><td>{2}</td></tr>"
+            "<tr><td>Available:</td><td>{3}</td></tr>"
+            "</table>"
+        ).format(kind, microbitVersion, currentVersionStr, tag)
+        if currentVersion < latestVersion:
+            msg += self.tr("<p><b>Update available!</b></p>")
+
+        EricMessageBox.information(
+            None,
+            self.tr("{0} Version").format(kind),
+            msg,
+        )
+
+    @pyqtSlot()
+    def __saveMain(self):
+        """
+        Private slot to copy the current script as 'main.py' onto the
+        connected device.
+        """
+        self.__saveScriptToDevice("main.py")
+
+    @pyqtSlot()
+    def __saveScriptToDevice(self, scriptName=""):
+        """
+        Private method to save the current script onto the connected
+        device.
+
+        @param scriptName name of the file on the device
+        @type str
+        """
+        aw = ericApp().getObject("ViewManager").activeWindow()
+        if not aw:
+            return
+
+        title = (
+            self.tr("Save Script as '{0}'").format(scriptName)
+            if scriptName
+            else self.tr("Save Script")
+        )
+
+        if not (aw.isPyFile() or aw.isMicroPythonFile()):
+            yes = EricMessageBox.yesNo(
+                self.microPython,
+                title,
+                self.tr(
+                    """The current editor does not contain a Python"""
+                    """ script. Write it anyway?"""
+                ),
+            )
+            if not yes:
+                return
+
+        script = aw.text().strip()
+        if not script:
+            EricMessageBox.warning(
+                self.microPython, title, self.tr("""The script is empty. Aborting.""")
+            )
+            return
+
+        if not scriptName:
+            scriptName = os.path.basename(aw.getFileName())
+            scriptName, ok = QInputDialog.getText(
+                self.microPython,
+                title,
+                self.tr("Enter a file name on the device:"),
+                QLineEdit.EchoMode.Normal,
+                scriptName,
+            )
+            if not ok or not bool(scriptName):
+                return
+
+            title = self.tr("Save Script as '{0}'").format(scriptName)
+
+        commands = [
+            "fd = open('{0}', 'wb')".format(scriptName),
+            "f = fd.write",
+        ]
+        for line in script.splitlines():
+            commands.append("f(" + repr(line + "\n") + ")")
+        commands.append("fd.close()")
+        out, err = self.microPython.commandsInterface().execute(commands)
+        if err:
+            EricMessageBox.critical(
+                self.microPython,
+                title,
+                self.tr(
+                    """<p>The script could not be saved to the"""
+                    """ device.</p><p>Reason: {0}</p>"""
+                ).format(err.decode("utf-8")),
+            )
+
+        # reset the device
+        self.__resetDevice()
+
+    @pyqtSlot()
+    def __resetDevice(self):
+        """
+        Private slot to reset the connected device.
+        """
+        if self.getDeviceType() == "bbc_microbit":
+            # BBC micro:bit
+            self.microPython.commandsInterface().execute(
+                [
+                    "import microbit",
+                    "microbit.reset()",
+                ]
+            )
+        else:
+            # Calliope mini
+            self.microPython.commandsInterface().execute(
+                [
+                    "import calliope_mini",
+                    "calliope_mini.reset()",
+                ]
+            )
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        if self.getDeviceType() == "bbc_microbit":
+            # BBC micro:bit
+            if self._deviceData and self._deviceData["mpy_name"] == "circuitpython":
+                return Preferences.getMicroPython("CircuitPythonDocuUrl")
+            else:
+                return Preferences.getMicroPython("MicrobitDocuUrl")
+        else:
+            # Calliope mini
+            return Preferences.getMicroPython("CalliopeDocuUrl")
+
+    def getDownloadMenuEntries(self):
+        """
+        Public method to retrieve the entries for the downloads menu.
+
+        @return list of tuples with menu text and URL to be opened for each
+            entry
+        @rtype list of tuple of (str, str)
+        """
+        if self.getDeviceType() == "bbc_microbit":
+            if self.__isMicroBitV1():
+                return [
+                    (
+                        self.tr("MicroPython Firmware for BBC micro:bit V1"),
+                        Preferences.getMicroPython("MicrobitMicroPythonUrl"),
+                    ),
+                    (
+                        self.tr("DAPLink Firmware"),
+                        Preferences.getMicroPython("MicrobitFirmwareUrl"),
+                    ),
+                ]
+            elif self.__isMicroBitV2():
+                return [
+                    (
+                        self.tr("MicroPython Firmware for BBC micro:bit V2"),
+                        Preferences.getMicroPython("MicrobitV2MicroPythonUrl"),
+                    ),
+                    (
+                        self.tr("CircuitPython Firmware for BBC micro:bit V2"),
+                        "https://circuitpython.org/board/microbit_v2/",
+                    ),
+                    (
+                        self.tr("DAPLink Firmware"),
+                        Preferences.getMicroPython("MicrobitFirmwareUrl"),
+                    ),
+                ]
+            else:
+                return []
+        else:
+            return [
+                (
+                    self.tr("MicroPython Firmware"),
+                    Preferences.getMicroPython("CalliopeMicroPythonUrl"),
+                ),
+                (
+                    self.tr("DAPLink Firmware"),
+                    Preferences.getMicroPython("CalliopeDAPLinkUrl"),
+                ),
+            ]
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype MicrobitDevice
+    """
+    return MicrobitDevice(microPythonWidget, deviceType, serialNumber)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/PyBoardDevices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,523 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for PyBoard boards.
+"""
+
+import os
+
+from PyQt6.QtCore import QStandardPaths, QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
+from PyQt6.QtWidgets import QMenu
+
+from eric7 import Globals, Preferences
+from eric7.EricWidgets import EricFileDialog, EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+from eric7.EricWidgets.EricProcessDialog import EricProcessDialog
+from eric7.SystemUtilities import FileSystemUtilities
+
+from . import FirmwareGithubUrls
+from .DeviceBase import BaseDevice
+from ..MicroPythonWidget import HAS_QTCHART
+
+
+class PyBoardDevice(BaseDevice):
+    """
+    Class implementing the device for PyBoard boards.
+    """
+
+    DeviceVolumeName = "PYBFLASH"
+
+    FlashInstructionsURL = (
+        "https://github.com/micropython/micropython/wiki/Pyboard-Firmware-Update"
+    )
+
+    def __init__(self, microPythonWidget, deviceType, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__workspace = self.__findWorkspace()
+
+        self.__createPyboardMenu()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+        if self.__deviceVolumeMounted():
+            self.microPython.setActionButtons(open=True, save=True)
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return False
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.tr("PyBoard")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def supportsLocalFileAccess(self):
+        """
+        Public method to indicate file access via a local directory.
+
+        @return flag indicating file access via local directory
+        @rtype bool
+        """
+        return self.__deviceVolumeMounted()
+
+    def __deviceVolumeMounted(self):
+        """
+        Private method to check, if the device volume is mounted.
+
+        @return flag indicated a mounted device
+        @rtype bool
+        """
+        if self.__workspace and not os.path.exists(self.__workspace):
+            self.__workspace = ""  # reset
+
+        return self.DeviceVolumeName in self.getWorkspace(silent=True)
+
+    def getWorkspace(self, silent=False):
+        """
+        Public method to get the workspace directory.
+
+        @param silent flag indicating silent operations
+        @type bool
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        if self.__workspace:
+            # return cached entry
+            return self.__workspace
+        else:
+            self.__workspace = self.__findWorkspace(silent=silent)
+            return self.__workspace
+
+    def __findWorkspace(self, silent=False):
+        """
+        Private method to find the workspace directory.
+
+        @param silent flag indicating silent operations
+        @type bool
+        @return workspace directory used for saving files
+        @rtype str
+        """
+        # Attempts to find the path on the filesystem that represents the
+        # plugged in PyBoard board.
+        deviceDirectories = FileSystemUtilities.findVolume(
+            self.DeviceVolumeName, findAll=True
+        )
+
+        if deviceDirectories:
+            if len(deviceDirectories) == 1:
+                return deviceDirectories[0]
+            else:
+                return self.selectDeviceDirectory(deviceDirectories)
+        else:
+            # return the default workspace and give the user a warning (unless
+            # silent mode is selected)
+            if not silent:
+                EricMessageBox.warning(
+                    self.microPython,
+                    self.tr("Workspace Directory"),
+                    self.tr(
+                        "Python files for PyBoard can be edited in"
+                        " place, if the device volume is locally"
+                        " available. Such a volume was not found. In"
+                        " place editing will not be available."
+                    ),
+                )
+
+            return super().getWorkspace()
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonDocuUrl")
+
+    def getFirmwareUrl(self):
+        """
+        Public method to get the device firmware download URL.
+
+        @return firmware download URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonFirmwareUrl")
+
+    def __createPyboardMenu(self):
+        """
+        Private method to create the pyboard submenu.
+        """
+        self.__pyboardMenu = QMenu(self.tr("PyBoard Functions"))
+
+        self.__showMpyAct = self.__pyboardMenu.addAction(
+            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
+        )
+        self.__pyboardMenu.addSeparator()
+        self.__bootloaderAct = self.__pyboardMenu.addAction(
+            self.tr("Activate Bootloader"), self.__activateBootloader
+        )
+        self.__dfuAct = self.__pyboardMenu.addAction(
+            self.tr("List DFU-capable Devices"), self.__listDfuCapableDevices
+        )
+        self.__pyboardMenu.addSeparator()
+        self.__flashMpyAct = self.__pyboardMenu.addAction(
+            self.tr("Flash MicroPython Firmware"), self.__flashMicroPython
+        )
+        self.__pyboardMenu.addAction(
+            self.tr("MicroPython Flash Instructions"), self.__showFlashInstructions
+        )
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        connected = self.microPython.isConnected()
+        linkConnected = self.microPython.isLinkConnected()
+
+        self.__bootloaderAct.setEnabled(connected)
+        self.__dfuAct.setEnabled(not linkConnected)
+        self.__showMpyAct.setEnabled(connected)
+        self.__flashMpyAct.setEnabled(not linkConnected)
+
+        menu.addMenu(self.__pyboardMenu)
+
+    def hasFlashMenuEntry(self):
+        """
+        Public method to check, if the device has its own flash menu entry.
+
+        @return flag indicating a specific flash menu entry
+        @rtype bool
+        """
+        return True
+
+    @pyqtSlot()
+    def __showFlashInstructions(self):
+        """
+        Private slot to open the URL containing instructions for installing
+        MicroPython on the pyboard.
+        """
+        ericApp().getObject("UserInterface").launchHelpViewer(
+            PyBoardDevice.FlashInstructionsURL
+        )
+
+    def __dfuUtilAvailable(self):
+        """
+        Private method to check the availability of dfu-util.
+
+        @return flag indicating the availability of dfu-util
+        @rtype bool
+        """
+        available = False
+        program = Preferences.getMicroPython("DfuUtilPath")
+        if not program:
+            program = "dfu-util"
+            if FileSystemUtilities.isinpath(program):
+                available = True
+        else:
+            if FileSystemUtilities.isExecutable(program):
+                available = True
+
+        if not available:
+            EricMessageBox.critical(
+                self.microPython,
+                self.tr("dfu-util not available"),
+                self.tr(
+                    """The dfu-util firmware flashing tool"""
+                    """ <b>dfu-util</b> cannot be found or is not"""
+                    """ executable. Ensure it is in the search path"""
+                    """ or configure it on the MicroPython"""
+                    """ configuration page."""
+                ),
+            )
+
+        return available
+
+    def __showDfuEnableInstructions(self, flash=True):
+        """
+        Private method to show some instructions to enable the DFU mode.
+
+        @param flash flag indicating to show a warning message for flashing
+        @type bool
+        @return flag indicating OK to continue or abort
+        @rtype bool
+        """
+        msg = self.tr(
+            "<h3>Enable DFU Mode</h3>"
+            "<p>1. Disconnect everything from your board</p>"
+            "<p>2. Disconnect your board</p>"
+            "<p>3. Connect the DFU/BOOT0 pin with a 3.3V pin</p>"
+            "<p>4. Re-connect your board</p>"
+            "<hr />"
+        )
+
+        if flash:
+            msg += self.tr(
+                "<p><b>Warning:</b> Make sure that all other DFU capable"
+                " devices except your PyBoard are disconnected."
+                "<hr />"
+            )
+
+        msg += self.tr("<p>Press <b>OK</b> to continue...</p>")
+        res = EricMessageBox.information(
+            self.microPython,
+            self.tr("Enable DFU mode"),
+            msg,
+            EricMessageBox.Abort | EricMessageBox.Ok,
+        )
+
+        return res == EricMessageBox.Ok
+
+    def __showDfuDisableInstructions(self):
+        """
+        Private method to show some instructions to disable the DFU mode.
+        """
+        msg = self.tr(
+            "<h3>Disable DFU Mode</h3>"
+            "<p>1. Disconnect your board</p>"
+            "<p>2. Remove the DFU jumper</p>"
+            "<p>3. Re-connect your board</p>"
+            "<hr />"
+            "<p>Press <b>OK</b> to continue...</p>"
+        )
+        EricMessageBox.information(self.microPython, self.tr("Disable DFU mode"), msg)
+
+    @pyqtSlot()
+    def __listDfuCapableDevices(self):
+        """
+        Private slot to list all DFU-capable devices.
+        """
+        if self.__dfuUtilAvailable():
+            ok2continue = self.__showDfuEnableInstructions(flash=False)
+            if ok2continue:
+                program = Preferences.getMicroPython("DfuUtilPath")
+                if not program:
+                    program = "dfu-util"
+
+                args = [
+                    "--list",
+                ]
+                dlg = EricProcessDialog(
+                    self.tr("'dfu-util' Output"), self.tr("List DFU capable Devices")
+                )
+                res = dlg.startProcess(program, args)
+                if res:
+                    dlg.exec()
+
+    @pyqtSlot()
+    def __flashMicroPython(self):
+        """
+        Private slot to flash a MicroPython firmware.
+        """
+        if self.__dfuUtilAvailable():
+            ok2continue = self.__showDfuEnableInstructions()
+            if ok2continue:
+                program = Preferences.getMicroPython("DfuUtilPath")
+                if not program:
+                    program = "dfu-util"
+
+                downloadsPath = QStandardPaths.standardLocations(
+                    QStandardPaths.StandardLocation.DownloadLocation
+                )[0]
+                firmware = EricFileDialog.getOpenFileName(
+                    self.microPython,
+                    self.tr("Flash MicroPython Firmware"),
+                    downloadsPath,
+                    self.tr("MicroPython Firmware Files (*.dfu);;All Files (*)"),
+                )
+                if firmware and os.path.exists(firmware):
+                    args = [
+                        "--alt",
+                        "0",
+                        "--download",
+                        firmware,
+                    ]
+                    dlg = EricProcessDialog(
+                        self.tr("'dfu-util' Output"),
+                        self.tr("Flash MicroPython Firmware"),
+                    )
+                    res = dlg.startProcess(program, args)
+                    if res:
+                        dlg.exec()
+                        self.__showDfuDisableInstructions()
+
+    @pyqtSlot()
+    def __showFirmwareVersions(self):
+        """
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+        """
+        if self.microPython.isConnected():
+            if self._deviceData["mpy_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))
+
+    def __firmwareVersionResponse(self, reply):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        """
+        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 self._deviceData["mpy_version"] == "unknown":
+            currentVersionStr = self.tr("unknown")
+            currentVersion = (0, 0, 0)
+        else:
+            currentVersionStr = self._deviceData["mpy_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 __activateBootloader(self):
+        """
+        Private slot to activate the bootloader and disconnect.
+        """
+        if self.microPython.isConnected():
+            self.microPython.commandsInterface().execute(
+                [
+                    "import pyb",
+                    "pyb.bootloader()",
+                ]
+            )
+            # simulate pressing the disconnect button
+            self.microPython.on_connectButton_clicked()
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype PyBoardDevice
+    """
+    return PyBoardDevice(microPythonWidget, deviceType)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/RP2040Devices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,318 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2021 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for RP2040 based boards
+(e.g. Raspberry Pi Pico).
+"""
+
+from PyQt6.QtCore import QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
+from PyQt6.QtWidgets import QMenu
+
+from eric7 import Globals, Preferences
+from eric7.EricWidgets import EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+
+from . import FirmwareGithubUrls
+from .DeviceBase import BaseDevice
+from ..MicroPythonWidget import HAS_QTCHART
+
+
+class RP2040Device(BaseDevice):
+    """
+    Class implementing the device for RP2040 based boards.
+    """
+
+    def __init__(self, microPythonWidget, deviceType, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__createRP2040Menu()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return False
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.tr("RP2040")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def __createRP2040Menu(self):
+        """
+        Private method to create the RO2040 submenu.
+        """
+        self.__rp2040Menu = QMenu(self.tr("RP2040 Functions"))
+
+        self.__showMpyAct = self.__rp2040Menu.addAction(
+            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
+        )
+        self.__rp2040Menu.addSeparator()
+        self.__bootloaderAct = self.__rp2040Menu.addAction(
+            self.tr("Activate Bootloader"), self.__activateBootloader
+        )
+        self.__flashMpyAct = self.__rp2040Menu.addAction(
+            self.tr("Flash MicroPython Firmware"), self.__flashPython
+        )
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        connected = self.microPython.isConnected()
+        linkConnected = self.microPython.isLinkConnected()
+
+        self.__showMpyAct.setEnabled(connected)
+        self.__bootloaderAct.setEnabled(connected)
+        self.__flashMpyAct.setEnabled(not linkConnected)
+
+        menu.addMenu(self.__rp2040Menu)
+
+    def hasFlashMenuEntry(self):
+        """
+        Public method to check, if the device has its own flash menu entry.
+
+        @return flag indicating a specific flash menu entry
+        @rtype bool
+        """
+        return True
+
+    @pyqtSlot()
+    def __flashPython(self):
+        """
+        Private slot to flash a MicroPython firmware to the device.
+        """
+        from ..UF2FlashDialog import UF2FlashDialog
+
+        dlg = UF2FlashDialog(boardType="rp2040")
+        dlg.exec()
+
+    def __activateBootloader(self):
+        """
+        Private method to switch the board into 'bootloader' mode.
+        """
+        if self.microPython.isConnected():
+            self.microPython.commandsInterface().execute(
+                [
+                    "import machine",
+                    "machine.bootloader()",
+                ]
+            )
+            # simulate pressing the disconnect button
+            self.microPython.on_connectButton_clicked()
+
+    @pyqtSlot()
+    def __showFirmwareVersions(self):
+        """
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+        """
+        if self.microPython.isConnected():
+            if self._deviceData["mpy_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:
+                if self._deviceData["mpy_variant"] == "Pimoroni":
+                    # MicroPython with Pimoroni add-on libraries
+                    url = QUrl(FirmwareGithubUrls["pimoroni_pico"])
+                else:
+                    url = QUrl(FirmwareGithubUrls["micropython"])
+                ui = ericApp().getObject("UserInterface")
+                request = QNetworkRequest(url)
+                reply = ui.networkAccessManager().head(request)
+                reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
+
+    def __firmwareVersionResponse(self, reply):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        """
+        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 self._deviceData["mpy_version"] == "unknown":
+            currentVersionStr = self.tr("unknown")
+            currentVersion = (0, 0, 0)
+        else:
+            currentVersionStr = self._deviceData["mpy_version"]
+            currentVersion = Globals.versionToTuple(currentVersionStr)
+
+        msg = self.tr(
+            "<h4>MicroPython Version Information</h4>"
+            "<table>"
+            "<tr><td>Installed:</td><td>{0}</td><td></td></tr>"
+            "<tr><td>Available:</td><td>{1}</td><td>{2}</td></tr>"
+            "</table>"
+        ).format(
+            currentVersionStr,
+            tag,
+            self.tr("({0})").format(self._deviceData["mpy_variant"])
+            if self._deviceData["mpy_variant"]
+            else "",
+        )
+        if (
+            self._deviceData["mpy_variant"] not in ["Pimoroni"]
+            and currentVersion < latestVersion
+        ):
+            # cannot derive that info for 'Pimoroni' variant
+            msg += self.tr("<p><b>Update available!</b></p>")
+
+        EricMessageBox.information(
+            None,
+            self.tr("MicroPython Version"),
+            msg,
+        )
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonDocuUrl")
+
+    def getDownloadMenuEntries(self):
+        """
+        Public method to retrieve the entries for the downloads menu.
+
+        @return list of tuples with menu text and URL to be opened for each
+            entry
+        @rtype list of tuple of (str, str)
+        """
+        return [
+            (
+                self.tr("MicroPython Firmware"),
+                Preferences.getMicroPython("MicroPythonFirmwareUrl"),
+            ),
+            ("<separator>", ""),
+            (self.tr("Pimoroni Pico Firmware"), FirmwareGithubUrls["pimoroni_pico"]),
+            ("<separator>", ""),
+            (
+                self.tr("CircuitPython Firmware"),
+                Preferences.getMicroPython("CircuitPythonFirmwareUrl"),
+            ),
+            (
+                self.tr("CircuitPython Libraries"),
+                Preferences.getMicroPython("CircuitPythonLibrariesUrl"),
+            ),
+        ]
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype RP2040Device
+    """
+    return RP2040Device(microPythonWidget, deviceType)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/TeensyDevices.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,288 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the device interface class for Teensy boards with MicroPython.
+"""
+
+from PyQt6.QtCore import QProcess, QUrl, pyqtSlot
+from PyQt6.QtNetwork import QNetworkRequest
+from PyQt6.QtWidgets import QMenu
+
+from eric7 import Globals, Preferences
+from eric7.EricWidgets import EricMessageBox
+from eric7.EricWidgets.EricApplication import ericApp
+
+from . import FirmwareGithubUrls
+from .DeviceBase import BaseDevice
+from ..MicroPythonWidget import HAS_QTCHART
+
+
+class TeensyDevice(BaseDevice):
+    """
+    Class implementing the device for Teensy boards with MicroPython.
+    """
+
+    def __init__(self, microPythonWidget, deviceType, parent=None):
+        """
+        Constructor
+
+        @param microPythonWidget reference to the main MicroPython widget
+        @type MicroPythonWidget
+        @param deviceType device type assigned to this device interface
+        @type str
+        @param parent reference to the parent object
+        @type QObject
+        """
+        super().__init__(microPythonWidget, deviceType, parent)
+
+        self.__createTeensyMenu()
+
+    def setButtons(self):
+        """
+        Public method to enable the supported action buttons.
+        """
+        super().setButtons()
+        self.microPython.setActionButtons(
+            run=True, repl=True, files=True, chart=HAS_QTCHART
+        )
+
+    def forceInterrupt(self):
+        """
+        Public method to determine the need for an interrupt when opening the
+        serial connection.
+
+        @return flag indicating an interrupt is needed
+        @rtype bool
+        """
+        return False
+
+    def deviceName(self):
+        """
+        Public method to get the name of the device.
+
+        @return name of the device
+        @rtype str
+        """
+        return self.tr("Teensy")
+
+    def canStartRepl(self):
+        """
+        Public method to determine, if a REPL can be started.
+
+        @return tuple containing a flag indicating it is safe to start a REPL
+            and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canStartPlotter(self):
+        """
+        Public method to determine, if a Plotter can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def canRunScript(self):
+        """
+        Public method to determine, if a script can be executed.
+
+        @return tuple containing a flag indicating it is safe to start a
+            Plotter and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def runScript(self, script):
+        """
+        Public method to run the given Python script.
+
+        @param script script to be executed
+        @type str
+        """
+        pythonScript = script.split("\n")
+        self.sendCommands(pythonScript)
+
+    def canStartFileManager(self):
+        """
+        Public method to determine, if a File Manager can be started.
+
+        @return tuple containing a flag indicating it is safe to start a
+            File Manager and a reason why it cannot.
+        @rtype tuple of (bool, str)
+        """
+        return True, ""
+
+    def getDocumentationUrl(self):
+        """
+        Public method to get the device documentation URL.
+
+        @return documentation URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonDocuUrl")
+
+    def getFirmwareUrl(self):
+        """
+        Public method to get the device firmware download URL.
+
+        @return firmware download URL of the device
+        @rtype str
+        """
+        return Preferences.getMicroPython("MicroPythonFirmwareUrl")
+
+    def __createTeensyMenu(self):
+        """
+        Private method to create the microbit submenu.
+        """
+        self.__teensyMenu = QMenu(self.tr("Teensy Functions"))
+
+        self.__showMpyAct = self.__teensyMenu.addAction(
+            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
+        )
+        self.__teensyMenu.addSeparator()
+        self.__teensyMenu.addAction(
+            self.tr("MicroPython Flash Instructions"), self.__showFlashInstructions
+        )
+        self.__flashMpyAct = self.__teensyMenu.addAction(
+            self.tr("Flash MicroPython Firmware"), self.__startTeensyLoader
+        )
+        self.__flashMpyAct.setToolTip(
+            self.tr("Start the 'Teensy Loader' application to flash the Teensy device.")
+        )
+
+    def addDeviceMenuEntries(self, menu):
+        """
+        Public method to add device specific entries to the given menu.
+
+        @param menu reference to the context menu
+        @type QMenu
+        """
+        connected = self.microPython.isConnected()
+        linkConnected = self.microPython.isLinkConnected()
+
+        self.__showMpyAct.setEnabled(connected)
+        self.__flashMpyAct.setEnabled(not linkConnected)
+
+        menu.addMenu(self.__teensyMenu)
+
+    @pyqtSlot()
+    def __showFirmwareVersions(self):
+        """
+        Private slot to show the firmware version of the connected device and the
+        available firmware version.
+        """
+        if self.microPython.isConnected():
+            if self._deviceData["mpy_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))
+
+    def __firmwareVersionResponse(self, reply):
+        """
+        Private method handling the response of the latest version request.
+
+        @param reply reference to the reply object
+        @type QNetworkReply
+        """
+        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 self._deviceData["mpy_version"] == "unknown":
+            currentVersionStr = self.tr("unknown")
+            currentVersion = (0, 0, 0)
+        else:
+            currentVersionStr = self._deviceData["mpy_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,
+        )
+
+    def __showFlashInstructions(self):
+        """
+        Private method to show a message box with instruction to flash the Teensy.
+        """
+        EricMessageBox.information(
+            self.microPython,
+            self.tr("Flash MicroPython Firmware"),
+            self.tr(
+                """<p>Teensy 4.0 and Teensy 4.1 are flashed using the 'Teensy Loader'"""
+                """ application. Make sure you downloaded the MicroPython or"""
+                """ CircuitPython .hex file.</p>"""
+                """<p>See <a href="{0}">the PJRC Teensy web site</a>"""
+                """ for details.</p>"""
+            ).format("https://www.pjrc.com/teensy/loader.html"),
+        )
+
+    def __startTeensyLoader(self):
+        """
+        Private method to start the 'Teensy Loader' application.
+
+        Note: The application must be accessible via the application search path.
+        """
+        ok, _ = QProcess.startDetached("teensy")
+        if not ok:
+            EricMessageBox.warning(
+                self.microPython,
+                self.tr("Start 'Teensy Loader'"),
+                self.tr(
+                    """<p>The 'Teensy Loader' application <b>teensy</b> could not"""
+                    """ be started. Ensure it is in the application search path or"""
+                    """ start it manually.</p>"""
+                ),
+            )
+
+
+def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
+    """
+    Function to instantiate a MicroPython device object.
+
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param deviceType device type assigned to this device interface
+    @type str
+    @param vid vendor ID
+    @type int
+    @param pid product ID
+    @type int
+    @param boardName name of the board
+    @type str
+    @param serialNumber serial number of the board
+    @type str
+    @return reference to the instantiated device object
+    @rtype PyBoardDevice
+    """
+    return TeensyDevice(microPythonWidget, deviceType)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/eric7/MicroPython/Devices/__init__.py	Mon Feb 13 17:49:52 2023 +0100
@@ -0,0 +1,490 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package containing the device interface modules and device specific dialogs.
+"""
+
+import contextlib
+import importlib
+import logging
+
+from PyQt6.QtCore import QCoreApplication
+from PyQt6.QtSerialPort import QSerialPortInfo
+
+from eric7 import Preferences
+from eric7.EricGui import EricPixmapCache
+
+from .DeviceBase import BaseDevice
+
+SupportedBoards = {
+    "bbc_microbit": {
+        "ids": [
+            (0x0D28, 0x0204),  # micro:bit
+        ],
+        "description": "BBC micro:bit",
+        "icon": "microbitDevice",
+        "port_description": "BBC micro:bit CMSIS-DAP",
+        "module": ".MicrobitDevices",
+    },
+    "calliope": {
+        "ids": [
+            (0x0D28, 0x0204),  # Calliope mini
+        ],
+        "description": "Calliope mini",
+        "icon": "calliope_mini",
+        "port_description": "DAPLink CMSIS-DAP",
+        "module": ".MicrobitDevices",
+    },
+    "circuitpython": {
+        "ids": [
+            (0x0483, 0x572A),  # STMicroelectronics NUCLEO-F446RE - CPy
+            (0x04D8, 0xE799),  # Cytron Maker Zero SAMD21
+            (0x04D8, 0xEA2A),  # BHDynamics DynaLoRa_USB
+            (0x04D8, 0xEAD1),  # BH Dynamics DynOSSAT-EDU-EPS-v1.0
+            (0x04D8, 0xEAD2),  # BH Dynamics DynOSSAT-EDU-OBC-v1.0
+            (0x04D8, 0xEC44),  # maholli PyCubed
+            (0x04D8, 0xEC63),  # Kevin Neubauer CircuitBrains Basic
+            (0x04D8, 0xEC64),  # Kevin Neubauer CircuitBrains Deluxe
+            (0x04D8, 0xEC72),  # XinaBox CC03
+            (0x04D8, 0xEC75),  # XinaBox CS11
+            (0x04D8, 0xED5F),  # Itaca Innovation uChip CircuitPython
+            (0x04D8, 0xED94),  # maholli kicksat-sprite
+            (0x04D8, 0xEDB3),  # Capable Robot Programmable USB Hub
+            (0x04D8, 0xEDBE),  # maholli SAM32
+            (0x04D8, 0xEE8C),  # J&J Studios LLC datum-Distance
+            (0x04D8, 0xEE8D),  # J&J Studios LLC datum-IMU
+            (0x04D8, 0xEE8E),  # J&J Studios LLC datum-Light
+            (0x04D8, 0xEE8F),  # J&J Studios LLC datum-Weather
+            (0x04D8, 0xEF67),  # senseBox MCU
+            (0x054C, 0x0BC2),  # Sony Spresense
+            (0x1209, 0x2017),  # Benjamin Shockley Mini SAM M4
+            (0x1209, 0x3141),  # CrumpSpace CrumpS2
+            (0x1209, 0x3252),  # Targett Module Clip w/Wroom
+            (0x1209, 0x3253),  # Targett Module Clip w/Wrover
+            (0x1209, 0x4203),  # 42. Keebs Frood
+            (0x1209, 0x4D43),  # Robotics Masters Robo HAT MM1 M4
+            (0x1209, 0x4DDD),  # ODT CP Sapling
+            (0x1209, 0x4DDE),  # ODT CP Sapling M0 w/ SPI Flash
+            (0x1209, 0x4DDF),  # ODT CP Sapling Rev B
+            (0x1209, 0x4DF0),  # Oak Dev Tech Pixelwing ESP32S2
+            (0x1209, 0x4DF1),  # Oak Dev Tech BREAD2040
+            (0x1209, 0x4DF2),  # Oak Dev Tech CAST AWAY RP2040
+            (0x1209, 0x5A52),  # ZRichard RP2.65-F
+            (0x1209, 0x5BF0),  # Foosn Fomu
+            (0x1209, 0x7150),  # Electronic Cats Hunter Cat NFC
+            (0x1209, 0x7382),  # Invector Labs AB iLabs Challenger 840
+            (0x1209, 0x805A),  # Electronic Cats BastBLE
+            (0x1209, 0x8CAE),  # takayoshiotake Octave RP2040
+            (0x1209, 0xA182),  # Solder Party RP2040 Stamp
+            (0x1209, 0xB182),  # Solder Party BBQ20 Keyboard
+            (0x1209, 0xBAB0),  # Electronic Cats Bast WiFi
+            (0x1209, 0xBAB1),  # Electronic Cats Meow Meow
+            (0x1209, 0xBAB2),  # Electronic Cats CatWAN USBStick
+            (0x1209, 0xBAB3),  # Electronic Cats Bast Pro Mini M0
+            (0x1209, 0xBAB6),  # Electronic Cats Escornabot Makech
+            (0x1209, 0xBAB8),  # Electronic Cats NFC Copy Cat
+            (0x1209, 0xC051),  # Betrusted Simmel
+            (0x1209, 0xCB74),  # 0xCB Helios
+            (0x1209, 0xD10D),  # Diodes Delight Piunora
+            (0x1209, 0xD1B5),  # Radomir Dopieralski PewPew LCD
+            (0x1209, 0xE3E3),  # StackRduino M0 PRO
+            (0x1209, 0xEF00),  # 2231puppy E-Fidget
+            (0x1209, 0xF123),  # Electrolama minik
+            (0x1209, 0xF500),  # Silicognition LLC M4-Shim
+            (0x1209, 0xF502),  # Silicognition LLC RP2040-Shim
+            (0x16D0, 0x08C6),  # Pimoroni Keybow 2040
+            (0x16D0, 0x08C7),  # Pimoroni Tiny 2040 (8MB)
+            (0x16D0, 0x08C8),  # Pimoroni PicoSystem
+            (0x16D0, 0x10ED),  # Mechwild PillBug
+            (0x1915, 0xB001),  # Makerdiary Pitaya Go
+            (0x192F, 0xB1B2),  # WarmBit BluePixel nRF52840
+            (0x1B4F, 0x0015),  # SparkFun RedBoard Turbo Board
+            (0x1B4F, 0x0016),  # SparkFun SAMD51 Thing+
+            (0x1B4F, 0x0017),  # SparkFun LUMIDrive Board
+            (0x1B4F, 0x0020),  # SparkFun MicroMod SAMD51 Processor
+            (0x1B4F, 0x0021),  # SparkFun MicroMod nRF52840 Processor
+            (0x1B4F, 0x0024),  # SparkFun MicroMod RP2040 Processor
+            (0x1B4F, 0x0025),  # SparkFun Thing Plus RP2040
+            (0x1B4F, 0x0026),  # SparkFun Pro Micro RP2040
+            (0x1B4F, 0x0027),  # SparkFun STM32 MicroMod Processor
+            (0x1B4F, 0x0028),  # SparkFun Thing Plus - STM32
+            (0x1B4F, 0x002E),  # PJRC/Sparkfun Teensy MicroMod
+            (0x1B4F, 0x5289),  # SparkFun SFE_nRF52840_Mini
+            (0x1B4F, 0x8D22),  # SparkFun SAMD21 Mini Breakout
+            (0x1B4F, 0x8D23),  # SparkFun SAMD21 Dev Breakout
+            (0x1B4F, 0x8D24),  # SparkFun Qwiic Micro
+            (0x1D50, 0x60E8),  # Radomir Dopieralski PewPew M4
+            (0x1D50, 0x6152),  # nrf52.jpconstantineau.com BlueMicro833
+            (0x1D50, 0x6153),  # JPConstantineau PyKey18
+            (0x1D50, 0x6153),  # JPConstantineau PyKey44
+            (0x1D50, 0x6153),  # JPConstantineau PyKey60
+            (0x1D50, 0x6153),  # JPConstantineau PyKey87
+            (0x1D50, 0x6154),  # JPConstantineau EncoderPad RP2040
+            (0x1D50, 0x6161),  # nrf52.jpconstantineau.com BlueMicro840
+            (0x2019, 0x7103),  # Benjamin Shockley Fig Pi
+            (0x2341, 0x8053),  # Arduino MKR1300
+            (0x2341, 0x8057),  # Arduino Nano 33 IoT
+            (0x2341, 0x805A),  # Arduino Arduino_Nano_33_BLE
+            (0x2341, 0x824D),  # Arduino Zero
+            (0x2786, 0x9207),  # Switch Sc. BLE-SS dev board Multi Sensor
+            (0x2786, 0x920D),  # Switch Sc. SSCI ISP1807 Dev Board
+            (0x2786, 0x920F),  # Switch Sc. SSCI ISP1807 Micro Board
+            (0x2886, 0x002F),  # Seeed Seeeduino XIAO
+            (0x2886, 0x0042),  # Seeed Seeeduino XIAO RP2040
+            (0x2886, 0x0045),  # Seeed XIAO nRF52840 Sense
+            (0x2886, 0x802D),  # Seeed Seeeduino Wio Terminal
+            (0x2886, 0x802F),  # Seeed Seeeduino XIAO KB
+            (0x2886, 0xF001),  # Makerdiary nRF52840 M.2 Developer Kit
+            (0x2886, 0xF002),  # Makerdiary M60 Keyboard
+            (0x2B04, 0xC00C),  # Particle Argon
+            (0x2B04, 0xC00D),  # Particle Boron
+            (0x2B04, 0xC00E),  # Particle Xenon
+            (0x2E8A, 0x1000),  # Cytron Maker Pi RP2040
+            (0x2E8A, 0x1002),  # Pimoroni Pico LiPo (4MB)
+            (0x2E8A, 0x1003),  # Pimoroni Pico LiPo (16MB)
+            (0x2E8A, 0x1005),  # Melopero Shake RP2040
+            (0x2E8A, 0x1006),  # Invector Labs Challenger RP2040 WiFi
+            (0x2E8A, 0x1008),  # Pimoroni PGA2040
+            (0x2E8A, 0x1009),  # Pimoroni Interstate 75
+            (0x2E8A, 0x100A),  # Pimoroni Plasma 2040
+            (0x2E8A, 0x100B),  # Invector Labs Challenger RP2040 LTE
+            (0x2E8A, 0x100D),  # Invector Labs Challenger NB RP2040 WiFi
+            (0x2E8A, 0x100E),  # Raspberry Pi Zero
+            (0x2E8A, 0x100F),  # Cytron Maker Nano RP2040
+            (0x2E8A, 0x1012),  # Raspberry Pi Compute Module 4 IO Board
+            (0x2E8A, 0x1013),  # Raspberry Pi 4B
+            (0x2E8A, 0x1014),  # Raspberry Pi Compute Module 4
+            (0x2E8A, 0x1015),  # Raspberry Pi Zero 2W
+            (0x2E8A, 0x1016),  # Pimoroni Tiny 2040 (2MB)
+            (0x2E8A, 0x1019),  # Pimoroni Motor 2040
+            (0x2E8A, 0x101A),  # Pimoroni Servo 2040
+            (0x2E8A, 0x101B),  # Pimoroni Badger 2040
+            (0x2E8A, 0x101E),  # Raspberry Pi Zero W
+            (0x2E8A, 0x101F),  # Waveshare Electronics RP2040-Zero
+            (0x2E8A, 0x1023),  # Invector Labs Challenger RP2040 LoRa
+            (0x2E8A, 0x1026),  # ELECFREAKS Pico:ed
+            (0x2E8A, 0x1027),  # WIZnet W5100S-EVB-Pico
+            (0x2E8A, 0x1029),  # WIZnet W5500-EVB-Pico
+            (0x2E8A, 0x102C),  # Invector Labs Challenger RP2040 WiFi/BLE
+            (0x2E8A, 0x102D),  # Invector Labs Challenger RP2040 SD/RTC
+            (0x2E8A, 0x102E),  # VCC-GND Studio YD-RP2040
+            (0x2E8A, 0x1032),  # Invector Labs Challenger RP2040 SubGHz
+            (0x2E8A, 0x1039),  # Waveshare Electronics Waveshare RP2040-LCD-1.28
+            (0x2E8A, 0x1048),  # nullbits Bit-C PRO
+            (0x303A, 0x7001),  # Espressif ESP32-S2-HMI-DevKit-1
+            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1
+            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N32R8
+            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N8
+            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N8R2
+            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N8R8
+            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-nopsram
+            (0x303A, 0x7005),  # Espressif ESP32-S3-Box-2.5
+            (0x303A, 0x7007),  # Espressif ESP32-S3-DevKitM-1-N8
+            (0x303A, 0x7009),  # Espressif ESP32-S2-DevKitC-1-N4
+            (0x303A, 0x7009),  # Espressif ESP32-S2-DevKitC-1-N4R2
+            (0x303A, 0x7009),  # Espressif ESP32-S2-DevKitC-1-N8R2
+            (0x303A, 0x700B),  # Espressif ESP32-S3-USB-OTG-N8
+            (0x303A, 0x700D),  # Espressif ESP32-S3-Box-Lite
+            (0x303A, 0x700F),  # Espressif ESP32-S3-EYE
+            (0x303A, 0x8002),  # UnexpectedMaker TinyS2
+            (0x303A, 0x8007),  # LILYGO TTGO T8 ESP32-S2
+            (0x303A, 0x800D),  # Gravitech Cucumber RS
+            (0x303A, 0x80A1),  # Gravitech Cucumber R
+            (0x303A, 0x80A4),  # Gravitech Cucumber M
+            (0x303A, 0x80A7),  # Gravitech Cucumber MS
+            (0x303A, 0x80AA),  # Espressif Franzininho WIFI w/Wroom
+            (0x303A, 0x80AD),  # Espressif Franzininho WIFI w/Wrover
+            (0x303A, 0x80AF),  # Artisense Reference Design RD00
+            (0x303A, 0x80B2),  # Muselab nanoESP32-S2  w/Wrover
+            (0x303A, 0x80B5),  # UnexpectedMaker FeatherS2 Neo
+            (0x303A, 0x80B7),  # MORPHEANS MORPHESP-240
+            (0x303A, 0x80C3),  # Lolin S2 Mini
+            (0x303A, 0x80C6),  # Lolin S2 Pico
+            (0x303A, 0x80D1),  # UnexpectedMaker TinyS3
+            (0x303A, 0x80D4),  # UnexpectedMaker ProS3
+            (0x303A, 0x80D7),  # UnexpectedMaker FeatherS3
+            (0x303A, 0x80D9),  # FutureKeys HexKy_S2
+            (0x303A, 0x80E0),  # BananaPi BPI-Leaf-S3
+            (0x303A, 0x80E6),  # BananaPi BPI-Bit-S2
+            (0x303A, 0x80E8),  # HiiBot IoTs2
+            (0x303A, 0x80EA),  # LILYGO TTGO T8 ESP32-S2-WROOM
+            (0x303A, 0x80ED),  # LILYGO TTGO T8 ESP32-S2
+            (0x303A, 0x80F9),  # Cytron Maker Feather AIoT S3
+            (0x303A, 0x80FC),  # Espressif MixGo CE
+            (0x303A, 0x80FD),  # Espressif MixGo CE
+            (0x303A, 0x810A),  # Waveshare Electronics ESP32-S2-Pico
+            (0x303A, 0x810C),  # Waveshare Electronics ESP32-S2-Pico-LCD
+            (0x303A, 0x8111),  # Smart Bee Designs Bee-S3
+            (0x303A, 0x8114),  # Smart Bee Designs Bee-Motion-S3
+            (0x303A, 0x8117),  # WEMOS LOLIN S3 16MB Flash 8MB PSRAM
+            (0x303A, 0x812C),  # BananaPi BPI-PicoW-S3
+            (0x30A4, 0x0002),  # Blues Inc. Swan R5
+            (0x3171, 0x0101),  # 8086.net Commander
+            (0x31E2, 0x2001),  # BDMICRO LLC VINA-D21
+            (0x31E2, 0x2011),  # BDMICRO LLC VINA-D51
+            (0x31E2, 0x2021),  # BDMICRO LLC VINA-D51
+            (0x32BD, 0x3001),  # Alorium Tech. AloriumTech Evo M51
+            (0x4097, 0x0001),  # TG-Boards Datalore IP M4
+            (0x612B, 0x80A7),  # Ai-Thinker ESP 12k NodeMCU
+            (0x239A, None),  # Any Adafruit Boards
+        ],
+        "description": "CircuitPython",
+        "icon": "circuitPythonDevice",
+        "port_description": "",
+        "module": ".CircuitPythonDevices",
+    },
+    "esp": {
+        "ids": [
+            (0x0403, 0x6001),  # M5Stack ESP32 device"),
+            (0x0403, 0x6001),  # FT232/FT245 (XinaBox CW01, CW02)
+            (0x0403, 0x6010),  # FT2232C/D/L/HL/Q (ESP-WROVER-KIT)
+            (0x0403, 0x6011),  # FT4232
+            (0x0403, 0x6014),  # FT232H
+            (0x0403, 0x6015),  # Sparkfun ESP32
+            (0x0403, 0x601C),  # FT4222H
+            (0x10C4, 0xEA60),  # CP210x
+            (0x1A86, 0x55D4),  # CH343
+            (0x1A86, 0x7523),  # HL-340, CH340
+        ],
+        "description": "ESP32, ESP8266",
+        "icon": "esp32Device",
+        "port_description": "",
+        "module": ".EspDevices",
+    },
+    "generic": {
+        # only manually configured devices use this
+        "ids": [],
+        "description": QCoreApplication.translate("MicroPythonDevice", "Generic Board"),
+        "icon": "micropython48",
+        "port_description": "",
+        "module": ".GenericMicroPythonDevices",
+    },
+    "pyboard": {
+        "ids": [
+            (0xF055, 0x9800),  # Pyboard in CDC mode
+            (0xF055, 0x9801),  # Pyboard in CDC+HID mode
+            (0xF055, 0x9802),  # Pyboard in CDC+MSC mode
+        ],
+        "description": "PyBoard",
+        "icon": "micropython48",
+        "port_description": "Pyboard",
+        "module": ".PyBoardDevices",
+    },
+    "rp2040": {
+        "ids": [
+            (0x2E8A, 0x0005),  # Raspberry Pi Pico
+        ],
+        "description": QCoreApplication.translate("MicroPythonDevice", "RP2040 based"),
+        "icon": "rp2040Device",
+        "port_description": "",
+        "module": ".RP2040Devices",
+    },
+    "teensy": {
+        "ids": [
+            (0xF055, 0x9802),  # Pyboard in CDC+MSC mode
+        ],
+        "description": "Teensy",
+        "icon": "micropython48",
+        "port_description": "Teensy",
+        "module": ".TeensyDevices",
+    },
+}
+
+IgnoredBoards = (
+    (0x8086, 0x9C3D),
+    (0x8086, None),
+)
+
+FirmwareGithubUrls = {
+    "micropython": "https://github.com/micropython/micropython/releases/latest",
+    "circuitpython": "https://github.com/adafruit/circuitpython/releases/latest",
+    "pimoroni_pico": "https://github.com/pimoroni/pimoroni-pico/releases/latest",
+    "microbit_v1": "https://github.com/bbcmicrobit/micropython/releases/latest",
+    "microbit_v2": (
+        "https://github.com/microbit-foundation/micropython-microbit-v2/releases/latest"
+    ),
+}
+
+
+def getSupportedDevices():
+    """
+    Function to get a list of supported MicroPython devices.
+
+    @return set of tuples with the board type and description
+    @rtype set of tuples of (str, str)
+    """
+    boards = []
+    for board in SupportedBoards:
+        boards.append((board, SupportedBoards[board]["description"]))
+    return boards
+
+
+def getFoundDevices():
+    """
+    Function to check the serial ports for supported MicroPython devices.
+
+    @return tuple containing a list of tuples with the board type, the port
+        description, a description, the serial port it is connected at, the
+        VID and PID for known device types, a list of tuples with VID, PID
+        and description for unknown devices and a list of tuples with VID,
+        PID, description and port name for ports with missing VID or PID
+    @rtype tuple of (list of tuples of (str, str, str, str, int, int),
+        list of tuples of (int, int, str),
+        list of tuples of (int, int, str, str)
+    """
+    foundDevices = []
+    unknownDevices = []
+    unknownPorts = []
+
+    manualDevices = {}
+    for deviceDict in Preferences.getMicroPython("ManualDevices"):
+        manualDevices[(deviceDict["vid"], deviceDict["pid"])] = deviceDict
+
+    availablePorts = QSerialPortInfo.availablePorts()
+    for port in availablePorts:
+        if port.hasVendorIdentifier() and port.hasProductIdentifier():
+            supported = False
+            vid = port.vendorIdentifier()
+            pid = port.productIdentifier()
+
+            for board in SupportedBoards:
+                if (vid, pid) in SupportedBoards[board]["ids"] or (
+                    vid,
+                    None,
+                ) in SupportedBoards[board]["ids"]:
+                    if board in ("bbc_microbit", "calliope") and (
+                        port.description().strip()
+                        != SupportedBoards[board]["port_description"]
+                    ):
+                        # both boards have the same VID and PID
+                        # try to differentiate based on port description
+                        continue
+                    elif board in ("pyboard", "teensy") and (
+                        not port.description().startswith(
+                            SupportedBoards[board]["port_description"]
+                        )
+                    ):
+                        # both boards have the same VID and PID
+                        # try to differentiate based on port description
+                        continue
+                    foundDevices.append(
+                        (
+                            board,
+                            port.description(),
+                            SupportedBoards[board]["description"],
+                            port.portName(),
+                            vid,
+                            pid,
+                            port.serialNumber(),
+                        )
+                    )
+                    supported = True
+            if not supported and (vid, pid) in manualDevices:
+                # check the locally added ones next
+                board = manualDevices[(vid, pid)]["type"]
+                foundDevices.append(
+                    (
+                        board,
+                        port.description(),
+                        SupportedBoards[board]["description"],
+                        port.portName(),
+                        vid,
+                        pid,
+                        port.serialNumber(),
+                    )
+                )
+                supported = True
+            if not supported:
+                if vid and pid:
+                    if (vid, pid) not in IgnoredBoards and (
+                        vid,
+                        None,
+                    ) not in IgnoredBoards:
+                        unknownDevices.append((vid, pid, port.description()))
+                        logging.debug(
+                            "Unknown device: (0x%04x:0x%04x %s)",
+                            vid,
+                            pid,
+                            port.description(),
+                        )
+                else:
+                    # either VID or PID or both not detected
+                    desc = port.description()
+                    if not desc:
+                        desc = QCoreApplication.translate(
+                            "MicroPythonDevice", "Unknown Device"
+                        )
+                    unknownPorts.append((vid, pid, desc, port.portName()))
+
+        elif bool(port.portName()) and Preferences.getMicroPython(
+            "EnableManualDeviceSelection"
+        ):
+            # no VID and/or PID available (e.g. in Linux container of ChromeOS)
+            desc = port.description()
+            if not desc:
+                desc = QCoreApplication.translate("MicroPythonDevice", "Unknown Device")
+            unknownPorts.append((0, 0, desc, port.portName()))
+
+    return foundDevices, unknownDevices, unknownPorts
+
+
+def getDeviceIcon(boardName, iconFormat=True):
+    """
+    Function to get the icon for the given board.
+
+    @param boardName name of the board
+    @type str
+    @param iconFormat flag indicating to get an icon or a pixmap
+    @type bool
+    @return icon for the board (iconFormat == True) or
+        a pixmap (iconFormat == False)
+    @rtype QIcon or QPixmap
+    """
+    iconName = (
+        SupportedBoards[boardName]["icon"]
+        if boardName in SupportedBoards
+        else
+        # return a generic MicroPython icon
+        "micropython48"
+    )
+
+    if iconFormat:
+        return EricPixmapCache.getIcon(iconName)
+    else:
+        return EricPixmapCache.getPixmap(iconName)
+
+
+def getDevice(deviceType, microPythonWidget, vid, pid, boardName="", serialNumber=""):
+    """
+    Public method to instantiate a specific MicroPython device interface.
+
+    @param deviceType type of the device interface
+    @type str
+    @param microPythonWidget reference to the main MicroPython widget
+    @type MicroPythonWidget
+    @param vid vendor ID (only used for deviceType 'generic')
+    @type int
+    @param pid product ID (only used for deviceType 'generic')
+    @type int
+    @param boardName name of the board (defaults to "")
+    @type str (optional)
+    @param serialNumber serial number of the board (defaults to "")
+    @type str (optional)
+    @return instantiated device interface
+    @rtype BaseDevice
+    """
+
+    with contextlib.suppress(KeyError):
+        mod = importlib.import_module(
+            SupportedBoards[deviceType]["module"], __package__
+        )
+        if mod:
+            return mod.createDevice(
+                microPythonWidget, deviceType, vid, pid, boardName, serialNumber
+            )
+
+    # nothing specific requested or specific one failed or is not supported yet
+    return BaseDevice(microPythonWidget, deviceType)
--- a/src/eric7/MicroPython/EspBackupRestoreFirmwareDialog.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to select the ESP chip type and the backup and
-restore parameters.
-"""
-
-import os
-
-from PyQt6.QtCore import pyqtSlot
-from PyQt6.QtWidgets import QDialog, QDialogButtonBox
-
-from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
-
-from .Ui_EspBackupRestoreFirmwareDialog import Ui_EspBackupRestoreFirmwareDialog
-
-
-class EspBackupRestoreFirmwareDialog(QDialog, Ui_EspBackupRestoreFirmwareDialog):
-    """
-    Class implementing a dialog to select the ESP chip type and the backup and
-    restore parameters.
-    """
-
-    Chips = (
-        ("", ""),
-        ("ESP32", "esp32"),
-        ("ESP32-C3", "esp32c3"),
-        ("ESP32-S2", "esp32s2"),
-        ("ESP32-S3", "esp32s3"),
-        ("ESP8266", "esp8266"),
-    )
-
-    FlashModes = [
-        ("", ""),
-        ("Quad I/O", "qio"),
-        ("Quad Output", "qout"),
-        ("Dual I/O", "dio"),
-        ("Dual Output", "dout"),
-    ]
-
-    FlashSizes = {
-        "esp32": [
-            (" 1 MB", "0x100000"),
-            (" 2 MB", "0x200000"),
-            (" 4 MB", "0x400000"),
-            (" 8 MB", "0x800000"),
-            ("16 MB", "0x1000000"),
-        ],
-        "esp32c3": [
-            (" 1 MB", "0x100000"),
-            (" 2 MB", "0x200000"),
-            (" 4 MB", "0x400000"),
-            (" 8 MB", "0x800000"),
-            ("16 MB", "0x1000000"),
-        ],
-        "esp32s2": [
-            (" 1 MB", "0x100000"),
-            (" 2 MB", "0x200000"),
-            (" 4 MB", "0x400000"),
-            (" 8 MB", "0x800000"),
-            ("16 MB", "0x1000000"),
-        ],
-        "esp32s3": [
-            (" 1 MB", "0x100000"),
-            (" 2 MB", "0x200000"),
-            (" 4 MB", "0x400000"),
-            (" 8 MB", "0x800000"),
-            ("16 MB", "0x1000000"),
-        ],
-        "esp8266": [
-            ("256 KB", "0x40000"),
-            ("512 KB", "0x80000"),
-            (" 1 MB", "0x100000"),
-            (" 2 MB", "0x200000"),
-            (" 4 MB", "0x400000"),
-            (" 8 MB", "0x800000"),
-            ("16 MB", "0x1000000"),
-        ],
-    }
-
-    def __init__(self, backupMode=True, parent=None):
-        """
-        Constructor
-
-        @param backupMode flag indicating parameters for a firmware backup are
-            requested
-        @type bool
-        @param parent reference to the parent widget
-        @type QWidget
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-
-        self.__isBackupMode = backupMode
-
-        for text, chip in self.Chips:
-            self.espComboBox.addItem(text, chip)
-
-        self.baudRateComboBox.addItems(
-            ["74.880", "115.200", "230.400", "460.800", "921.600", "1.500.000"]
-        )
-        self.baudRateComboBox.setCurrentIndex(3)
-
-        self.firmwarePicker.setFilters(self.tr("Firmware Files (*.img);;All Files (*)"))
-        if self.__isBackupMode:
-            self.firmwarePicker.setMode(
-                EricPathPickerModes.SAVE_FILE_ENSURE_EXTENSION_MODE
-            )
-            self.sizeInfoLabel.clear()
-            self.modeComboBox.setEnabled(False)
-            self.modeInfoLabel.setEnabled(False)
-            self.setWindowTitle(self.tr("Backup Firmware"))
-        else:
-            self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
-            for text, mode in self.FlashModes:
-                self.modeComboBox.addItem(text, mode)
-            self.setWindowTitle(self.tr("Restore Firmware"))
-
-        msh = self.minimumSizeHint()
-        self.resize(max(self.width(), msh.width()), msh.height())
-
-    def __updateOkButton(self):
-        """
-        Private method to update the state of the OK button.
-        """
-        firmwareFile = self.firmwarePicker.text()
-        enable = bool(self.espComboBox.currentText()) and bool(firmwareFile)
-        if self.__isBackupMode:
-            enable &= bool(self.sizeComboBox.currentText())
-        else:
-            enable &= os.path.exists(firmwareFile)
-        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable)
-
-    @pyqtSlot(str)
-    def on_espComboBox_currentTextChanged(self, chip):
-        """
-        Private slot to handle the selection of a chip type.
-
-        @param chip selected chip type
-        @type str
-        """
-        selectedSize = self.sizeComboBox.currentText()
-        self.sizeComboBox.clear()
-        chipType = self.espComboBox.currentData()
-        if chipType and chipType in self.FlashSizes:
-            self.sizeComboBox.addItem("")
-            for text, data in self.FlashSizes[chipType]:
-                self.sizeComboBox.addItem(text, data)
-
-            self.sizeComboBox.setCurrentText(selectedSize)
-
-        self.__updateOkButton()
-
-    @pyqtSlot(str)
-    def on_sizeComboBox_currentTextChanged(self, size):
-        """
-        Private slot handling a change of the selected firmware size.
-
-        @param size selected size text
-        @type str
-        """
-        self.__updateOkButton()
-
-    @pyqtSlot(str)
-    def on_firmwarePicker_textChanged(self, firmware):
-        """
-        Private slot handling a change of the firmware path.
-
-        @param firmware path to the firmware
-        @type str
-        """
-        self.__updateOkButton()
-
-    def getData(self):
-        """
-        Public method to get the entered data.
-
-        @return tuple containing the selected chip type, the firmware size,
-            the baud rate or flashing, the flash mode and the path of the
-            firmware file
-        @rtype tuple of (str, str, str, str, str)
-        """
-        flashSize = (
-            self.sizeComboBox.currentData()
-            if self.__isBackupMode
-            else self.sizeComboBox.currentText().replace(" ", "")
-        )
-
-        return (
-            self.espComboBox.currentData(),
-            flashSize,
-            self.baudRateComboBox.currentText().replace(".", ""),
-            self.modeComboBox.currentData(),
-            self.firmwarePicker.text(),
-        )
--- a/src/eric7/MicroPython/EspDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,593 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for ESP32 and ESP8266 based
-boards.
-"""
-
-from PyQt6.QtCore import QProcess, QUrl, pyqtSlot
-from PyQt6.QtNetwork import QNetworkRequest
-from PyQt6.QtWidgets import QDialog, QMenu
-
-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 FirmwareGithubUrls, MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class EspDevice(MicroPythonDevice):
-    """
-    Class implementing the device for ESP32 and ESP8266 based boards.
-    """
-
-    def __init__(self, microPythonWidget, deviceType, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__createEsp32Submenu()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return True
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.tr("ESP8266, ESP32")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def __createEsp32Submenu(self):
-        """
-        Private method to create the ESP32 submenu.
-        """
-        self.__espMenu = QMenu(self.tr("ESP32 Functions"))
-
-        self.__showMpyAct = self.__espMenu.addAction(
-            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
-        )
-        self.__espMenu.addSeparator()
-        self.__eraseFlashAct = self.__espMenu.addAction(
-            self.tr("Erase Flash"), self.__eraseFlash
-        )
-        self.__flashMpyAct = self.__espMenu.addAction(
-            self.tr("Flash MicroPython Firmware"), self.__flashMicroPython
-        )
-        self.__espMenu.addSeparator()
-        self.__flashAdditionalAct = self.__espMenu.addAction(
-            self.tr("Flash Additional Firmware"), self.__flashAddons
-        )
-        self.__espMenu.addSeparator()
-        self.__backupAct = self.__espMenu.addAction(
-            self.tr("Backup Firmware"), self.__backupFlash
-        )
-        self.__restoreAct = self.__espMenu.addAction(
-            self.tr("Restore Firmware"), self.__restoreFlash
-        )
-        self.__espMenu.addSeparator()
-        self.__chipIdAct = self.__espMenu.addAction(
-            self.tr("Show Chip ID"), self.__showChipID
-        )
-        self.__flashIdAct = self.__espMenu.addAction(
-            self.tr("Show Flash ID"), self.__showFlashID
-        )
-        self.__macAddressAct = self.__espMenu.addAction(
-            self.tr("Show MAC Address"), self.__showMACAddress
-        )
-        self.__espMenu.addSeparator()
-        self.__resetAct = self.__espMenu.addAction(
-            self.tr("Reset Device"), self.__resetDevice
-        )
-        self.__espMenu.addSeparator()
-        self.__espMenu.addAction(self.tr("Install 'esptool.py'"), self.__installEspTool)
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        connected = self.microPython.isConnected()
-        linkConnected = self.microPython.isLinkConnected()
-
-        self.__showMpyAct.setEnabled(connected)
-        self.__eraseFlashAct.setEnabled(not linkConnected)
-        self.__flashMpyAct.setEnabled(not linkConnected)
-        self.__flashAdditionalAct.setEnabled(not linkConnected)
-        self.__backupAct.setEnabled(not linkConnected)
-        self.__restoreAct.setEnabled(not linkConnected)
-        self.__chipIdAct.setEnabled(not linkConnected)
-        self.__flashIdAct.setEnabled(not linkConnected)
-        self.__macAddressAct.setEnabled(not linkConnected)
-        self.__resetAct.setEnabled(connected or not linkConnected)
-
-        menu.addMenu(self.__espMenu)
-
-    def hasFlashMenuEntry(self):
-        """
-        Public method to check, if the device has its own flash menu entry.
-
-        @return flag indicating a specific flash menu entry
-        @rtype bool
-        """
-        return True
-
-    @pyqtSlot()
-    def __eraseFlash(self):
-        """
-        Private slot to erase the device flash memory.
-        """
-        ok = EricMessageBox.yesNo(
-            self.microPython,
-            self.tr("Erase Flash"),
-            self.tr("""Shall the flash of the selected device really be erased?"""),
-        )
-        if ok:
-            flashArgs = [
-                "-u",
-                "-m",
-                "esptool",
-                "--port",
-                self.microPython.getCurrentPort(),
-                "erase_flash",
-            ]
-            dlg = EricProcessDialog(
-                self.tr("'esptool erase_flash' Output"),
-                self.tr("Erase Flash"),
-                showProgress=True,
-            )
-            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
-            if res:
-                dlg.exec()
-
-    @pyqtSlot()
-    def __flashMicroPython(self):
-        """
-        Private slot to flash a MicroPython firmware to the device.
-        """
-        from .EspFirmwareSelectionDialog import EspFirmwareSelectionDialog
-
-        dlg = EspFirmwareSelectionDialog()
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            chip, firmware, baudRate, flashMode, flashAddress = dlg.getData()
-            flashArgs = [
-                "-u",
-                "-m",
-                "esptool",
-                "--chip",
-                chip,
-                "--port",
-                self.microPython.getCurrentPort(),
-            ]
-            if baudRate != "115200":
-                flashArgs += ["--baud", baudRate]
-            flashArgs.append("write_flash")
-            if flashMode:
-                flashArgs += ["--flash_mode", flashMode]
-            flashArgs += [
-                flashAddress,
-                firmware,
-            ]
-            dlg = EricProcessDialog(
-                self.tr("'esptool write_flash' Output"),
-                self.tr("Flash MicroPython Firmware"),
-                showProgress=True,
-            )
-            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
-            if res:
-                dlg.exec()
-
-    @pyqtSlot()
-    def __flashAddons(self):
-        """
-        Private slot to flash some additional firmware images.
-        """
-        from .EspFirmwareSelectionDialog import EspFirmwareSelectionDialog
-
-        dlg = EspFirmwareSelectionDialog(addon=True)
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            chip, firmware, baudRate, flashMode, flashAddress = dlg.getData()
-            flashArgs = [
-                "-u",
-                "-m",
-                "esptool",
-                "--chip",
-                chip,
-                "--port",
-                self.microPython.getCurrentPort(),
-            ]
-            if baudRate != "115200":
-                flashArgs += ["--baud", baudRate]
-            flashArgs.append("write_flash")
-            if flashMode:
-                flashArgs += ["--flash_mode", flashMode]
-            flashArgs += [
-                flashAddress.lower(),
-                firmware,
-            ]
-            dlg = EricProcessDialog(
-                self.tr("'esptool write_flash' Output"),
-                self.tr("Flash Additional Firmware"),
-                showProgress=True,
-            )
-            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
-            if res:
-                dlg.exec()
-
-    @pyqtSlot()
-    def __backupFlash(self):
-        """
-        Private slot to backup the currently flashed firmware.
-        """
-        from .EspBackupRestoreFirmwareDialog import EspBackupRestoreFirmwareDialog
-
-        dlg = EspBackupRestoreFirmwareDialog(backupMode=True)
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            chip, flashSize, baudRate, flashMode, firmware = dlg.getData()
-            flashArgs = [
-                "-u",
-                "-m",
-                "esptool",
-                "--chip",
-                chip,
-                "--port",
-                self.microPython.getCurrentPort(),
-                "--baud",
-                baudRate,
-                "read_flash",
-                "0x0",
-                flashSize,
-                firmware,
-            ]
-            dlg = EricProcessDialog(
-                self.tr("'esptool read_flash' Output"),
-                self.tr("Backup Firmware"),
-                showProgress=True,
-            )
-            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
-            if res:
-                dlg.exec()
-
-    @pyqtSlot()
-    def __restoreFlash(self):
-        """
-        Private slot to restore a previously saved firmware.
-        """
-        from .EspBackupRestoreFirmwareDialog import EspBackupRestoreFirmwareDialog
-
-        dlg = EspBackupRestoreFirmwareDialog(backupMode=False)
-        if dlg.exec() == QDialog.DialogCode.Accepted:
-            chip, flashSize, baudRate, flashMode, firmware = dlg.getData()
-            flashArgs = [
-                "-u",
-                "-m",
-                "esptool",
-                "--chip",
-                chip,
-                "--port",
-                self.microPython.getCurrentPort(),
-                "--baud",
-                baudRate,
-                "write_flash",
-            ]
-            if flashMode:
-                flashArgs.extend(
-                    [
-                        "--flash_mode",
-                        flashMode,
-                    ]
-                )
-            if bool(flashSize):
-                flashArgs.extend(
-                    [
-                        "--flash_size",
-                        flashSize,
-                    ]
-                )
-            flashArgs.extend(
-                [
-                    "0x0",
-                    firmware,
-                ]
-            )
-            dlg = EricProcessDialog(
-                self.tr("'esptool write_flash' Output"),
-                self.tr("Restore Firmware"),
-                showProgress=True,
-            )
-            res = dlg.startProcess(PythonUtilities.getPythonExecutable(), flashArgs)
-            if res:
-                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():
-            if self._deviceData["mpy_name"] == "micropython":
-                url = QUrl(FirmwareGithubUrls["micropython"])
-            elif self._deviceData["mpy_name"] == "circuitpython":
-                url = QUrl(FirmwareGithubUrls["circuitpython"])
-            else:
-                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"""
-                        """ or CircuitPython. Aborting..."""
-                    ),
-                )
-                return
-
-            ui = ericApp().getObject("UserInterface")
-            request = QNetworkRequest(url)
-            reply = ui.networkAccessManager().head(request)
-            reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
-
-    def __firmwareVersionResponse(self, reply):
-        """
-        Private method handling the response of the latest version request.
-
-        @param reply reference to the reply object
-        @type QNetworkReply
-        """
-        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 self._deviceData["mpy_version"] == "unknown":
-            currentVersionStr = self.tr("unknown")
-            currentVersion = (0, 0, 0)
-        else:
-            currentVersionStr = self._deviceData["mpy_version"]
-            currentVersion = Globals.versionToTuple(currentVersionStr)
-
-        if self._deviceData["mpy_name"] == "circuitpython":
-            kind = "CircuitPython"
-        elif self._deviceData["mpy_name"] == "micropython":
-            kind = "MicroPython"
-
-        msg = self.tr(
-            "<h4>{0} Version Information</h4>"
-            "<table>"
-            "<tr><td>Installed:</td><td>{1}</td></tr>"
-            "<tr><td>Available:</td><td>{2}</td></tr>"
-            "</table>"
-        ).format(kind, currentVersionStr, tag)
-        if currentVersion < latestVersion:
-            msg += self.tr("<p><b>Update available!</b></p>")
-
-        EricMessageBox.information(
-            None,
-            self.tr("{0} Version").format(kind),
-            msg,
-        )
-
-    @pyqtSlot()
-    def __showChipID(self):
-        """
-        Private slot to show the ID of the ESP chip.
-        """
-        args = [
-            "-u",
-            "-m",
-            "esptool",
-            "--port",
-            self.microPython.getCurrentPort(),
-            "chip_id",
-        ]
-        dlg = EricProcessDialog(
-            self.tr("'esptool chip_id' Output"), self.tr("Show Chip ID")
-        )
-        res = dlg.startProcess(PythonUtilities.getPythonExecutable(), args)
-        if res:
-            dlg.exec()
-
-    @pyqtSlot()
-    def __showFlashID(self):
-        """
-        Private slot to show the ID of the ESP flash chip.
-        """
-        args = [
-            "-u",
-            "-m",
-            "esptool",
-            "--port",
-            self.microPython.getCurrentPort(),
-            "flash_id",
-        ]
-        dlg = EricProcessDialog(
-            self.tr("'esptool flash_id' Output"), self.tr("Show Flash ID")
-        )
-        res = dlg.startProcess(PythonUtilities.getPythonExecutable(), args)
-        if res:
-            dlg.exec()
-
-    @pyqtSlot()
-    def __showMACAddress(self):
-        """
-        Private slot to show the MAC address of the ESP chip.
-        """
-        args = [
-            "-u",
-            "-m",
-            "esptool",
-            "--port",
-            self.microPython.getCurrentPort(),
-            "read_mac",
-        ]
-        dlg = EricProcessDialog(
-            self.tr("'esptool read_mac' Output"), self.tr("Show MAC Address")
-        )
-        res = dlg.startProcess(PythonUtilities.getPythonExecutable(), args)
-        if res:
-            dlg.exec()
-
-    @pyqtSlot()
-    def __resetDevice(self):
-        """
-        Private slot to reset the connected device.
-        """
-        if self.microPython.isConnected():
-            self.microPython.commandsInterface().execute(
-                [
-                    "import machine",
-                    "machine.reset()",
-                ]
-            )
-        else:
-            # perform a reset via esptool using flash_id command ignoring
-            # the output
-            args = [
-                "-u",
-                "-m",
-                "esptool",
-                "--port",
-                self.microPython.getCurrentPort(),
-                "flash_id",
-            ]
-            proc = QProcess()
-            proc.start(PythonUtilities.getPythonExecutable(), args)
-            procStarted = proc.waitForStarted(10000)
-            if procStarted:
-                proc.waitForFinished(10000)
-
-    @pyqtSlot()
-    def __installEspTool(self):
-        """
-        Private slot to install the esptool package via pip.
-        """
-        pip = ericApp().getObject("Pip")
-        pip.installPackages(
-            ["esptool"], interpreter=PythonUtilities.getPythonExecutable()
-        )
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonDocuUrl")
-
-    def getFirmwareUrl(self):
-        """
-        Public method to get the device firmware download URL.
-
-        @return firmware download URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonFirmwareUrl")
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype EspDevice
-    """
-    return EspDevice(microPythonWidget, deviceType)
--- a/src/eric7/MicroPython/EspFirmwareSelectionDialog.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing a dialog to select the ESP chip type and the firmware to
-be flashed.
-"""
-
-import os
-
-from PyQt6.QtCore import QRegularExpression, pyqtSlot
-from PyQt6.QtGui import QRegularExpressionValidator
-from PyQt6.QtWidgets import QDialog, QDialogButtonBox
-
-from eric7.EricWidgets.EricPathPicker import EricPathPickerModes
-
-from .Ui_EspFirmwareSelectionDialog import Ui_EspFirmwareSelectionDialog
-
-
-class EspFirmwareSelectionDialog(QDialog, Ui_EspFirmwareSelectionDialog):
-    """
-    Class implementing a dialog to select the ESP chip type and the firmware to
-    be flashed.
-    """
-
-    Chips = (
-        ("", ""),
-        ("ESP32", "esp32"),
-        ("ESP32-C3", "esp32c3"),
-        ("ESP32-S2", "esp32s2"),
-        ("ESP32-S3", "esp32s3"),
-        ("ESP8266", "esp8266"),
-    )
-
-    FlashModes = (
-        ("", ""),
-        ("Quad I/O", "qio"),
-        ("Quad Output", "qout"),
-        ("Dual I/O", "dio"),
-        ("Dual Output", "dout"),
-    )
-
-    FlashAddresses = {
-        "esp8266": "0x0000",
-        "esp32": "0x1000",
-        "esp32c3": "0x0000",
-        "esp32s2": "0x1000",
-        "esp32s3": "0x0000",
-    }
-
-    def __init__(self, addon=False, parent=None):
-        """
-        Constructor
-
-        @param addon flag indicating an addon firmware
-        @type bool
-        @param parent reference to the parent widget
-        @type QWidget
-        """
-        super().__init__(parent)
-        self.setupUi(self)
-
-        self.__addon = addon
-
-        self.firmwarePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
-        self.firmwarePicker.setFilters(self.tr("Firmware Files (*.bin);;All Files (*)"))
-
-        for text, chip in self.Chips:
-            self.espComboBox.addItem(text, chip)
-
-        self.baudRateComboBox.addItems(
-            ["74.880", "115.200", "230.400", "460.800", "921.600", "1.500.000"]
-        )
-        self.baudRateComboBox.setCurrentIndex(3)
-
-        for text, mode in self.FlashModes:
-            self.modeComboBox.addItem(text, mode)
-
-        if addon:
-            self.__validator = QRegularExpressionValidator(
-                QRegularExpression(r"[0-9a-fA-F]{0,7}")
-            )
-            self.addressEdit.setValidator(self.__validator)
-        else:
-            self.addressLabel.hide()
-            self.addressEdit.hide()
-
-        msh = self.minimumSizeHint()
-        self.resize(max(self.width(), msh.width()), msh.height())
-
-    def __updateOkButton(self):
-        """
-        Private method to update the state of the OK button.
-        """
-        firmwareFile = self.firmwarePicker.text()
-        enable = (
-            bool(self.espComboBox.currentText())
-            and bool(firmwareFile)
-            and os.path.exists(firmwareFile)
-        )
-        if self.__addon:
-            enable &= bool(self.addressEdit.text())
-        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable)
-
-    @pyqtSlot(str)
-    def on_espComboBox_currentTextChanged(self, chip):
-        """
-        Private slot to handle the selection of a chip type.
-
-        @param chip selected chip type
-        @type str
-        """
-        self.__updateOkButton()
-
-        self.cpyCheckBox.setEnabled(chip == "ESP32-S2")
-        # possible address override needed for CircuitPython
-
-    @pyqtSlot(str)
-    def on_firmwarePicker_textChanged(self, firmware):
-        """
-        Private slot handling a change of the firmware path.
-
-        @param firmware path to the firmware
-        @type str
-        """
-        self.__updateOkButton()
-
-        self.cpyCheckBox.setChecked("circuitpython" in firmware)
-        # possible address override needed for CircuitPython
-
-    @pyqtSlot(str)
-    def on_addressEdit_textChanged(self, address):
-        """
-        Private slot handling a change of the address.
-
-        @param address entered address
-        @type str
-        """
-        self.__updateOkButton()
-
-    def getData(self):
-        """
-        Public method to get the entered data.
-
-        @return tuple containing the selected chip type, the path of the
-            firmware file, the baud rate, the flash mode and the flash
-            address
-        @rtype tuple of (str, str, str, str, str)
-        """
-        chip = self.espComboBox.currentData()
-
-        address = self.addressEdit.text() if self.__addon else self.FlashAddresses[chip]
-        if not self.__addon and chip == "esp32s2" and self.cpyCheckBox.isChecked():
-            # override address
-            address = "0x0000"
-
-        return (
-            chip,
-            self.firmwarePicker.text(),
-            self.baudRateComboBox.currentText().replace(".", ""),
-            self.modeComboBox.currentData(),
-            address,
-        )
--- a/src/eric7/MicroPython/GenericMicroPythonDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for generic MicroPython devices
-(i.e. those devices not specifically supported yet).
-"""
-
-import os
-
-from eric7 import Preferences
-from eric7.EricWidgets import EricMessageBox
-from eric7.SystemUtilities import FileSystemUtilities
-
-from .MicroPythonDevices import MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class GenericMicroPythonDevice(MicroPythonDevice):
-    """
-    Class implementing the device interface for generic MicroPython boards.
-    """
-
-    def __init__(self, microPythonWidget, deviceType, vid, pid, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param vid vendor ID
-        @type int
-        @param pid product ID
-        @type int
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__directAccess = False
-        self.__deviceVolumeName = ""
-        self.__workspace = ""
-        self.__deviceName = ""
-
-        for deviceData in Preferences.getMicroPython("ManualDevices"):
-            if deviceData["vid"] == vid and deviceData["pid"] == pid:
-                self.__deviceVolumeName = deviceData["data_volume"]
-                self.__directAccess = bool(deviceData["data_volume"])
-                self.__deviceName = deviceData["description"]
-
-                if self.__directAccess:
-                    self.__workspace = self.__findWorkspace()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-        if self.__directAccess and self.__deviceVolumeMounted():
-            self.microPython.setActionButtons(open=True, save=True)
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.__deviceName
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def supportsLocalFileAccess(self):
-        """
-        Public method to indicate file access via a local directory.
-
-        @return flag indicating file access via local directory
-        @rtype bool
-        """
-        return self.__deviceVolumeMounted()
-
-    def __deviceVolumeMounted(self):
-        """
-        Private method to check, if the device volume is mounted.
-
-        @return flag indicated a mounted device
-        @rtype bool
-        """
-        if self.__workspace and not os.path.exists(self.__workspace):
-            self.__workspace = ""  # reset
-
-        return self.__directAccess and self.__deviceVolumeName in self.getWorkspace(
-            silent=True
-        )
-
-    def getWorkspace(self, silent=False):
-        """
-        Public method to get the workspace directory.
-
-        @param silent flag indicating silent operations
-        @type bool
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        if self.__directAccess:
-            if self.__workspace:
-                # return cached entry
-                return self.__workspace
-            else:
-                self.__workspace = self.__findWorkspace(silent=silent)
-                return self.__workspace
-        else:
-            return super().getWorkspace()
-
-    def __findWorkspace(self, silent=False):
-        """
-        Private method to find the workspace directory.
-
-        @param silent flag indicating silent operations
-        @type bool
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        # Attempts to find the path on the filesystem that represents the
-        # plugged in board.
-        deviceDirectories = FileSystemUtilities.findVolume(
-            self.__deviceVolumeName, findAll=True
-        )
-
-        if deviceDirectories:
-            if len(deviceDirectories) == 1:
-                return deviceDirectories[0]
-            else:
-                return self.selectDeviceDirectory(deviceDirectories)
-        else:
-            # return the default workspace and give the user a warning (unless
-            # silent mode is selected)
-            if not silent:
-                EricMessageBox.warning(
-                    self.microPython,
-                    self.tr("Workspace Directory"),
-                    self.tr(
-                        "Python files for this generic board can be"
-                        " edited in place, if the device volume is locally"
-                        " available. A volume named '{0}' was not found."
-                        " In place editing will not be available."
-                    ).format(self.__deviceVolumeName),
-                )
-
-            return super().getWorkspace()
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype GenericMicroPythonDevice
-    """
-    return GenericMicroPythonDevice(microPythonWidget, deviceType, vid, pid)
--- a/src/eric7/MicroPython/MicroPythonDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,836 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing some utility functions and the MicroPythonDevice base
-class.
-"""
-
-import contextlib
-import copy
-import importlib
-import logging
-import os
-
-from PyQt6.QtCore import QCoreApplication, QObject, pyqtSlot
-from PyQt6.QtSerialPort import QSerialPortInfo
-from PyQt6.QtWidgets import QInputDialog
-
-from eric7 import Preferences
-from eric7.EricGui import EricPixmapCache
-from eric7.EricWidgets import EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-
-SupportedBoards = {
-    "esp": {
-        "ids": [
-            (0x0403, 0x6001),  # M5Stack ESP32 device"),
-            (0x0403, 0x6001),  # FT232/FT245 (XinaBox CW01, CW02)
-            (0x0403, 0x6010),  # FT2232C/D/L/HL/Q (ESP-WROVER-KIT)
-            (0x0403, 0x6011),  # FT4232
-            (0x0403, 0x6014),  # FT232H
-            (0x0403, 0x6015),  # Sparkfun ESP32
-            (0x0403, 0x601C),  # FT4222H
-            (0x10C4, 0xEA60),  # CP210x
-            (0x1A86, 0x55D4),  # CH343
-            (0x1A86, 0x7523),  # HL-340, CH340
-        ],
-        "description": "ESP32, ESP8266",
-        "icon": "esp32Device",
-        "port_description": "",
-    },
-    "circuitpython": {
-        "ids": [
-            (0x0483, 0x572A),  # STMicroelectronics NUCLEO-F446RE - CPy
-            (0x04D8, 0xE799),  # Cytron Maker Zero SAMD21
-            (0x04D8, 0xEA2A),  # BHDynamics DynaLoRa_USB
-            (0x04D8, 0xEAD1),  # BH Dynamics DynOSSAT-EDU-EPS-v1.0
-            (0x04D8, 0xEAD2),  # BH Dynamics DynOSSAT-EDU-OBC-v1.0
-            (0x04D8, 0xEC44),  # maholli PyCubed
-            (0x04D8, 0xEC63),  # Kevin Neubauer CircuitBrains Basic
-            (0x04D8, 0xEC64),  # Kevin Neubauer CircuitBrains Deluxe
-            (0x04D8, 0xEC72),  # XinaBox CC03
-            (0x04D8, 0xEC75),  # XinaBox CS11
-            (0x04D8, 0xED5F),  # Itaca Innovation uChip CircuitPython
-            (0x04D8, 0xED94),  # maholli kicksat-sprite
-            (0x04D8, 0xEDB3),  # Capable Robot Programmable USB Hub
-            (0x04D8, 0xEDBE),  # maholli SAM32
-            (0x04D8, 0xEE8C),  # J&J Studios LLC datum-Distance
-            (0x04D8, 0xEE8D),  # J&J Studios LLC datum-IMU
-            (0x04D8, 0xEE8E),  # J&J Studios LLC datum-Light
-            (0x04D8, 0xEE8F),  # J&J Studios LLC datum-Weather
-            (0x04D8, 0xEF67),  # senseBox MCU
-            (0x054C, 0x0BC2),  # Sony Spresense
-            (0x1209, 0x2017),  # Benjamin Shockley Mini SAM M4
-            (0x1209, 0x3141),  # CrumpSpace CrumpS2
-            (0x1209, 0x3252),  # Targett Module Clip w/Wroom
-            (0x1209, 0x3253),  # Targett Module Clip w/Wrover
-            (0x1209, 0x4203),  # 42. Keebs Frood
-            (0x1209, 0x4D43),  # Robotics Masters Robo HAT MM1 M4
-            (0x1209, 0x4DDD),  # ODT CP Sapling
-            (0x1209, 0x4DDE),  # ODT CP Sapling M0 w/ SPI Flash
-            (0x1209, 0x4DDF),  # ODT CP Sapling Rev B
-            (0x1209, 0x4DF0),  # Oak Dev Tech Pixelwing ESP32S2
-            (0x1209, 0x4DF1),  # Oak Dev Tech BREAD2040
-            (0x1209, 0x4DF2),  # Oak Dev Tech CAST AWAY RP2040
-            (0x1209, 0x5A52),  # ZRichard RP2.65-F
-            (0x1209, 0x5BF0),  # Foosn Fomu
-            (0x1209, 0x7150),  # Electronic Cats Hunter Cat NFC
-            (0x1209, 0x7382),  # Invector Labs AB iLabs Challenger 840
-            (0x1209, 0x805A),  # Electronic Cats BastBLE
-            (0x1209, 0x8CAE),  # takayoshiotake Octave RP2040
-            (0x1209, 0xA182),  # Solder Party RP2040 Stamp
-            (0x1209, 0xB182),  # Solder Party BBQ20 Keyboard
-            (0x1209, 0xBAB0),  # Electronic Cats Bast WiFi
-            (0x1209, 0xBAB1),  # Electronic Cats Meow Meow
-            (0x1209, 0xBAB2),  # Electronic Cats CatWAN USBStick
-            (0x1209, 0xBAB3),  # Electronic Cats Bast Pro Mini M0
-            (0x1209, 0xBAB6),  # Electronic Cats Escornabot Makech
-            (0x1209, 0xBAB8),  # Electronic Cats NFC Copy Cat
-            (0x1209, 0xC051),  # Betrusted Simmel
-            (0x1209, 0xCB74),  # 0xCB Helios
-            (0x1209, 0xD10D),  # Diodes Delight Piunora
-            (0x1209, 0xD1B5),  # Radomir Dopieralski PewPew LCD
-            (0x1209, 0xE3E3),  # StackRduino M0 PRO
-            (0x1209, 0xEF00),  # 2231puppy E-Fidget
-            (0x1209, 0xF123),  # Electrolama minik
-            (0x1209, 0xF500),  # Silicognition LLC M4-Shim
-            (0x1209, 0xF502),  # Silicognition LLC RP2040-Shim
-            (0x16D0, 0x08C6),  # Pimoroni Keybow 2040
-            (0x16D0, 0x08C7),  # Pimoroni Tiny 2040 (8MB)
-            (0x16D0, 0x08C8),  # Pimoroni PicoSystem
-            (0x16D0, 0x10ED),  # Mechwild PillBug
-            (0x1915, 0xB001),  # Makerdiary Pitaya Go
-            (0x192F, 0xB1B2),  # WarmBit BluePixel nRF52840
-            (0x1B4F, 0x0015),  # SparkFun RedBoard Turbo Board
-            (0x1B4F, 0x0016),  # SparkFun SAMD51 Thing+
-            (0x1B4F, 0x0017),  # SparkFun LUMIDrive Board
-            (0x1B4F, 0x0020),  # SparkFun MicroMod SAMD51 Processor
-            (0x1B4F, 0x0021),  # SparkFun MicroMod nRF52840 Processor
-            (0x1B4F, 0x0024),  # SparkFun MicroMod RP2040 Processor
-            (0x1B4F, 0x0025),  # SparkFun Thing Plus RP2040
-            (0x1B4F, 0x0026),  # SparkFun Pro Micro RP2040
-            (0x1B4F, 0x0027),  # SparkFun STM32 MicroMod Processor
-            (0x1B4F, 0x0028),  # SparkFun Thing Plus - STM32
-            (0x1B4F, 0x002E),  # PJRC/Sparkfun Teensy MicroMod
-            (0x1B4F, 0x5289),  # SparkFun SFE_nRF52840_Mini
-            (0x1B4F, 0x8D22),  # SparkFun SAMD21 Mini Breakout
-            (0x1B4F, 0x8D23),  # SparkFun SAMD21 Dev Breakout
-            (0x1B4F, 0x8D24),  # SparkFun Qwiic Micro
-            (0x1D50, 0x60E8),  # Radomir Dopieralski PewPew M4
-            (0x1D50, 0x6152),  # nrf52.jpconstantineau.com BlueMicro833
-            (0x1D50, 0x6153),  # JPConstantineau PyKey18
-            (0x1D50, 0x6153),  # JPConstantineau PyKey44
-            (0x1D50, 0x6153),  # JPConstantineau PyKey60
-            (0x1D50, 0x6153),  # JPConstantineau PyKey87
-            (0x1D50, 0x6154),  # JPConstantineau EncoderPad RP2040
-            (0x1D50, 0x6161),  # nrf52.jpconstantineau.com BlueMicro840
-            (0x2019, 0x7103),  # Benjamin Shockley Fig Pi
-            (0x2341, 0x8053),  # Arduino MKR1300
-            (0x2341, 0x8057),  # Arduino Nano 33 IoT
-            (0x2341, 0x805A),  # Arduino Arduino_Nano_33_BLE
-            (0x2341, 0x824D),  # Arduino Zero
-            (0x2786, 0x9207),  # Switch Sc. BLE-SS dev board Multi Sensor
-            (0x2786, 0x920D),  # Switch Sc. SSCI ISP1807 Dev Board
-            (0x2786, 0x920F),  # Switch Sc. SSCI ISP1807 Micro Board
-            (0x2886, 0x002F),  # Seeed Seeeduino XIAO
-            (0x2886, 0x0042),  # Seeed Seeeduino XIAO RP2040
-            (0x2886, 0x0045),  # Seeed XIAO nRF52840 Sense
-            (0x2886, 0x802D),  # Seeed Seeeduino Wio Terminal
-            (0x2886, 0x802F),  # Seeed Seeeduino XIAO KB
-            (0x2886, 0xF001),  # Makerdiary nRF52840 M.2 Developer Kit
-            (0x2886, 0xF002),  # Makerdiary M60 Keyboard
-            (0x2B04, 0xC00C),  # Particle Argon
-            (0x2B04, 0xC00D),  # Particle Boron
-            (0x2B04, 0xC00E),  # Particle Xenon
-            (0x2E8A, 0x1000),  # Cytron Maker Pi RP2040
-            (0x2E8A, 0x1002),  # Pimoroni Pico LiPo (4MB)
-            (0x2E8A, 0x1003),  # Pimoroni Pico LiPo (16MB)
-            (0x2E8A, 0x1005),  # Melopero Shake RP2040
-            (0x2E8A, 0x1006),  # Invector Labs Challenger RP2040 WiFi
-            (0x2E8A, 0x1008),  # Pimoroni PGA2040
-            (0x2E8A, 0x1009),  # Pimoroni Interstate 75
-            (0x2E8A, 0x100A),  # Pimoroni Plasma 2040
-            (0x2E8A, 0x100B),  # Invector Labs Challenger RP2040 LTE
-            (0x2E8A, 0x100D),  # Invector Labs Challenger NB RP2040 WiFi
-            (0x2E8A, 0x100E),  # Raspberry Pi Zero
-            (0x2E8A, 0x100F),  # Cytron Maker Nano RP2040
-            (0x2E8A, 0x1012),  # Raspberry Pi Compute Module 4 IO Board
-            (0x2E8A, 0x1013),  # Raspberry Pi 4B
-            (0x2E8A, 0x1014),  # Raspberry Pi Compute Module 4
-            (0x2E8A, 0x1015),  # Raspberry Pi Zero 2W
-            (0x2E8A, 0x1016),  # Pimoroni Tiny 2040 (2MB)
-            (0x2E8A, 0x1019),  # Pimoroni Motor 2040
-            (0x2E8A, 0x101A),  # Pimoroni Servo 2040
-            (0x2E8A, 0x101B),  # Pimoroni Badger 2040
-            (0x2E8A, 0x101E),  # Raspberry Pi Zero W
-            (0x2E8A, 0x101F),  # Waveshare Electronics RP2040-Zero
-            (0x2E8A, 0x1023),  # Invector Labs Challenger RP2040 LoRa
-            (0x2E8A, 0x1026),  # ELECFREAKS Pico:ed
-            (0x2E8A, 0x1027),  # WIZnet W5100S-EVB-Pico
-            (0x2E8A, 0x1029),  # WIZnet W5500-EVB-Pico
-            (0x2E8A, 0x102C),  # Invector Labs Challenger RP2040 WiFi/BLE
-            (0x2E8A, 0x102D),  # Invector Labs Challenger RP2040 SD/RTC
-            (0x2E8A, 0x102E),  # VCC-GND Studio YD-RP2040
-            (0x2E8A, 0x1032),  # Invector Labs Challenger RP2040 SubGHz
-            (0x2E8A, 0x1039),  # Waveshare Electronics Waveshare RP2040-LCD-1.28
-            (0x2E8A, 0x1048),  # nullbits Bit-C PRO
-            (0x303A, 0x7001),  # Espressif ESP32-S2-HMI-DevKit-1
-            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1
-            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N32R8
-            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N8
-            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N8R2
-            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-N8R8
-            (0x303A, 0x7003),  # Espressif ESP32-S3-DevKitC-1-nopsram
-            (0x303A, 0x7005),  # Espressif ESP32-S3-Box-2.5
-            (0x303A, 0x7007),  # Espressif ESP32-S3-DevKitM-1-N8
-            (0x303A, 0x7009),  # Espressif ESP32-S2-DevKitC-1-N4
-            (0x303A, 0x7009),  # Espressif ESP32-S2-DevKitC-1-N4R2
-            (0x303A, 0x7009),  # Espressif ESP32-S2-DevKitC-1-N8R2
-            (0x303A, 0x700B),  # Espressif ESP32-S3-USB-OTG-N8
-            (0x303A, 0x700D),  # Espressif ESP32-S3-Box-Lite
-            (0x303A, 0x700F),  # Espressif ESP32-S3-EYE
-            (0x303A, 0x8002),  # UnexpectedMaker TinyS2
-            (0x303A, 0x8007),  # LILYGO TTGO T8 ESP32-S2
-            (0x303A, 0x800D),  # Gravitech Cucumber RS
-            (0x303A, 0x80A1),  # Gravitech Cucumber R
-            (0x303A, 0x80A4),  # Gravitech Cucumber M
-            (0x303A, 0x80A7),  # Gravitech Cucumber MS
-            (0x303A, 0x80AA),  # Espressif Franzininho WIFI w/Wroom
-            (0x303A, 0x80AD),  # Espressif Franzininho WIFI w/Wrover
-            (0x303A, 0x80AF),  # Artisense Reference Design RD00
-            (0x303A, 0x80B2),  # Muselab nanoESP32-S2  w/Wrover
-            (0x303A, 0x80B5),  # UnexpectedMaker FeatherS2 Neo
-            (0x303A, 0x80B7),  # MORPHEANS MORPHESP-240
-            (0x303A, 0x80C3),  # Lolin S2 Mini
-            (0x303A, 0x80C6),  # Lolin S2 Pico
-            (0x303A, 0x80D1),  # UnexpectedMaker TinyS3
-            (0x303A, 0x80D4),  # UnexpectedMaker ProS3
-            (0x303A, 0x80D7),  # UnexpectedMaker FeatherS3
-            (0x303A, 0x80D9),  # FutureKeys HexKy_S2
-            (0x303A, 0x80E0),  # BananaPi BPI-Leaf-S3
-            (0x303A, 0x80E6),  # BananaPi BPI-Bit-S2
-            (0x303A, 0x80E8),  # HiiBot IoTs2
-            (0x303A, 0x80EA),  # LILYGO TTGO T8 ESP32-S2-WROOM
-            (0x303A, 0x80ED),  # LILYGO TTGO T8 ESP32-S2
-            (0x303A, 0x80F9),  # Cytron Maker Feather AIoT S3
-            (0x303A, 0x80FC),  # Espressif MixGo CE
-            (0x303A, 0x80FD),  # Espressif MixGo CE
-            (0x303A, 0x810A),  # Waveshare Electronics ESP32-S2-Pico
-            (0x303A, 0x810C),  # Waveshare Electronics ESP32-S2-Pico-LCD
-            (0x303A, 0x8111),  # Smart Bee Designs Bee-S3
-            (0x303A, 0x8114),  # Smart Bee Designs Bee-Motion-S3
-            (0x303A, 0x8117),  # WEMOS LOLIN S3 16MB Flash 8MB PSRAM
-            (0x303A, 0x812C),  # BananaPi BPI-PicoW-S3
-            (0x30A4, 0x0002),  # Blues Inc. Swan R5
-            (0x3171, 0x0101),  # 8086.net Commander
-            (0x31E2, 0x2001),  # BDMICRO LLC VINA-D21
-            (0x31E2, 0x2011),  # BDMICRO LLC VINA-D51
-            (0x31E2, 0x2021),  # BDMICRO LLC VINA-D51
-            (0x32BD, 0x3001),  # Alorium Tech. AloriumTech Evo M51
-            (0x4097, 0x0001),  # TG-Boards Datalore IP M4
-            (0x612B, 0x80A7),  # Ai-Thinker ESP 12k NodeMCU
-            (0x239A, None),  # Any Adafruit Boards
-        ],
-        "description": "CircuitPython",
-        "icon": "circuitPythonDevice",
-        "port_description": "",
-    },
-    "bbc_microbit": {
-        "ids": [
-            (0x0D28, 0x0204),  # micro:bit
-        ],
-        "description": "BBC micro:bit",
-        "icon": "microbitDevice",
-        "port_description": "BBC micro:bit CMSIS-DAP",
-    },
-    "calliope": {
-        "ids": [
-            (0x0D28, 0x0204),  # Calliope mini
-        ],
-        "description": "Calliope mini",
-        "icon": "calliope_mini",
-        "port_description": "DAPLink CMSIS-DAP",
-    },
-    "pyboard": {
-        "ids": [
-            (0xF055, 0x9800),  # Pyboard in CDC mode
-            (0xF055, 0x9801),  # Pyboard in CDC+HID mode
-            (0xF055, 0x9802),  # Pyboard in CDC+MSC mode
-        ],
-        "description": "PyBoard",
-        "icon": "micropython48",
-        "port_description": "Pyboard",
-    },
-    "rp2040": {
-        "ids": [
-            (0x2E8A, 0x0005),  # Raspberry Pi Pico
-        ],
-        "description": QCoreApplication.translate("MicroPythonDevice", "RP2040 based"),
-        "icon": "rp2040Device",
-        "port_description": "",
-    },
-    "teensy": {
-        "ids": [
-            (0xF055, 0x9802),  # Pyboard in CDC+MSC mode
-        ],
-        "description": "Teensy",
-        "icon": "micropython48",
-        "port_description": "Teensy",
-    },
-    "generic": {
-        # only manually configured devices use this
-        "ids": [],
-        "description": QCoreApplication.translate("MicroPythonDevice", "Generic Board"),
-        "icon": "micropython48",
-        "port_description": "",
-    },
-}
-
-IgnoredBoards = (
-    (0x8086, 0x9C3D),
-    (0x8086, None),
-)
-
-FirmwareGithubUrls = {
-    "micropython": "https://github.com/micropython/micropython/releases/latest",
-    "circuitpython": "https://github.com/adafruit/circuitpython/releases/latest",
-    "pimoroni_pico": "https://github.com/pimoroni/pimoroni-pico/releases/latest",
-    "microbit_v1": "https://github.com/bbcmicrobit/micropython/releases/latest",
-    "microbit_v2": (
-        "https://github.com/microbit-foundation/micropython-microbit-v2/releases/latest"
-    ),
-}
-
-
-def getSupportedDevices():
-    """
-    Function to get a list of supported MicroPython devices.
-
-    @return set of tuples with the board type and description
-    @rtype set of tuples of (str, str)
-    """
-    boards = []
-    for board in SupportedBoards:
-        boards.append((board, SupportedBoards[board]["description"]))
-    return boards
-
-
-def getFoundDevices():
-    """
-    Function to check the serial ports for supported MicroPython devices.
-
-    @return tuple containing a list of tuples with the board type, the port
-        description, a description, the serial port it is connected at, the
-        VID and PID for known device types, a list of tuples with VID, PID
-        and description for unknown devices and a list of tuples with VID,
-        PID, description and port name for ports with missing VID or PID
-    @rtype tuple of (list of tuples of (str, str, str, str, int, int),
-        list of tuples of (int, int, str),
-        list of tuples of (int, int, str, str)
-    """
-    foundDevices = []
-    unknownDevices = []
-    unknownPorts = []
-
-    manualDevices = {}
-    for deviceDict in Preferences.getMicroPython("ManualDevices"):
-        manualDevices[(deviceDict["vid"], deviceDict["pid"])] = deviceDict
-
-    availablePorts = QSerialPortInfo.availablePorts()
-    for port in availablePorts:
-        if port.hasVendorIdentifier() and port.hasProductIdentifier():
-            supported = False
-            vid = port.vendorIdentifier()
-            pid = port.productIdentifier()
-
-            for board in SupportedBoards:
-                if (vid, pid) in SupportedBoards[board]["ids"] or (
-                    vid,
-                    None,
-                ) in SupportedBoards[board]["ids"]:
-                    if board in ("bbc_microbit", "calliope") and (
-                        port.description().strip()
-                        != SupportedBoards[board]["port_description"]
-                    ):
-                        # both boards have the same VID and PID
-                        # try to differentiate based on port description
-                        continue
-                    elif board in ("pyboard", "teensy") and (
-                        not port.description().startswith(
-                            SupportedBoards[board]["port_description"]
-                        )
-                    ):
-                        # both boards have the same VID and PID
-                        # try to differentiate based on port description
-                        continue
-                    foundDevices.append(
-                        (
-                            board,
-                            port.description(),
-                            SupportedBoards[board]["description"],
-                            port.portName(),
-                            vid,
-                            pid,
-                            port.serialNumber(),
-                        )
-                    )
-                    supported = True
-            if not supported and (vid, pid) in manualDevices:
-                # check the locally added ones next
-                board = manualDevices[(vid, pid)]["type"]
-                foundDevices.append(
-                    (
-                        board,
-                        port.description(),
-                        SupportedBoards[board]["description"],
-                        port.portName(),
-                        vid,
-                        pid,
-                        port.serialNumber(),
-                    )
-                )
-                supported = True
-            if not supported:
-                if vid and pid:
-                    if (vid, pid) not in IgnoredBoards and (
-                        vid,
-                        None,
-                    ) not in IgnoredBoards:
-                        unknownDevices.append((vid, pid, port.description()))
-                        logging.debug(
-                            "Unknown device: (0x%04x:0x%04x %s)",
-                            vid,
-                            pid,
-                            port.description(),
-                        )
-                else:
-                    # either VID or PID or both not detected
-                    desc = port.description()
-                    if not desc:
-                        desc = QCoreApplication.translate(
-                            "MicroPythonDevice", "Unknown Device"
-                        )
-                    unknownPorts.append((vid, pid, desc, port.portName()))
-
-        elif bool(port.portName()) and Preferences.getMicroPython(
-            "EnableManualDeviceSelection"
-        ):
-            # no VID and/or PID available (e.g. in Linux container of ChromeOS)
-            desc = port.description()
-            if not desc:
-                desc = QCoreApplication.translate("MicroPythonDevice", "Unknown Device")
-            unknownPorts.append((0, 0, desc, port.portName()))
-
-    return foundDevices, unknownDevices, unknownPorts
-
-
-def getDeviceIcon(boardName, iconFormat=True):
-    """
-    Function to get the icon for the given board.
-
-    @param boardName name of the board
-    @type str
-    @param iconFormat flag indicating to get an icon or a pixmap
-    @type bool
-    @return icon for the board (iconFormat == True) or
-        a pixmap (iconFormat == False)
-    @rtype QIcon or QPixmap
-    """
-    iconName = (
-        SupportedBoards[boardName]["icon"]
-        if boardName in SupportedBoards
-        else
-        # return a generic MicroPython icon
-        "micropython48"
-    )
-
-    if iconFormat:
-        return EricPixmapCache.getIcon(iconName)
-    else:
-        return EricPixmapCache.getPixmap(iconName)
-
-
-def getDevice(deviceType, microPythonWidget, vid, pid, boardName="", serialNumber=""):
-    """
-    Public method to instantiate a specific MicroPython device interface.
-
-    @param deviceType type of the device interface
-    @type str
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param vid vendor ID (only used for deviceType 'generic')
-    @type int
-    @param pid product ID (only used for deviceType 'generic')
-    @type int
-    @param boardName name of the board (defaults to "")
-    @type str (optional)
-    @param serialNumber serial number of the board (defaults to "")
-    @type str (optional)
-    @return instantiated device interface
-    @rtype MicroPythonDevice
-    """
-    deviceMapping = {
-        "bbc_microbit": ".MicrobitDevices",
-        "calliope": ".MicrobitDevices",
-        "circuitpython": ".CircuitPythonDevices",
-        "esp": ".EspDevices",
-        "generic": ".GenericMicroPythonDevices",
-        "pyboard": ".PyBoardDevices",
-        "rp2040": ".RP2040Devices",
-        "teensy": ".TeensyDevices",
-    }
-
-    with contextlib.suppress(KeyError):
-        mod = importlib.import_module(deviceMapping[deviceType], __package__)
-        if mod:
-            return mod.createDevice(
-                microPythonWidget, deviceType, vid, pid, boardName, serialNumber
-            )
-
-    # nothing specific requested or specific one failed or is not supported yet
-    return MicroPythonDevice(microPythonWidget, deviceType)
-
-
-class MicroPythonDevice(QObject):
-    """
-    Base class for the more specific MicroPython devices.
-    """
-
-    def __init__(self, microPythonWidget, deviceType, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(parent)
-
-        self._deviceType = deviceType
-        self.microPython = microPythonWidget
-        self._deviceData = {}  # dictionary with essential device data
-
-    def setConnected(self, connected):
-        """
-        Public method to set the connection state.
-
-        Note: This method can be overwritten to perform actions upon connect
-        or disconnect of the device.
-
-        @param connected connection state
-        @type bool
-        """
-        self._deviceData = {}
-
-        if connected:
-            with contextlib.suppress(OSError):
-                self._deviceData = self.microPython.commandsInterface().getDeviceData()
-
-    def getDeviceType(self):
-        """
-        Public method to get the device type.
-
-        @return type of the device
-        @rtype str
-        """
-        return self._deviceType
-
-    def getDeviceData(self):
-        """
-        Public method to get a copy of the determined device data.
-
-        @return dictionary containing the essential device data
-        @rtype dict
-        """
-        return copy.deepcopy(self._deviceData)
-
-    def checkDeviceData(self):
-        """
-        Public method to check the validity of the device data determined during
-        connecting the device.
-
-        @return flag indicating valid device data
-        @rtype bool
-        """
-        if bool(self._deviceData):
-            return True
-        else:
-            EricMessageBox.critical(
-                None,
-                self.tr("Show MicroPython Versions"),
-                self.tr(
-                    """<p>The device data is not available. Try to connect to the"""
-                    """ device again. Aborting...</p>"""
-                ).format(self.getDeviceType()),
-            )
-            return False
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        self.microPython.setActionButtons(
-            open=False, save=False, run=False, repl=False, files=False, chart=False
-        )
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return True
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.tr("Unsupported Device")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return False, self.tr("REPL is not supported by this device.")
-
-    def setRepl(self, on):
-        """
-        Public method to set the REPL status and dependent status.
-
-        @param on flag indicating the active status
-        @type bool
-        """
-        pass
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return False, self.tr("Plotter is not supported by this device.")
-
-    def setPlotter(self, on):
-        """
-        Public method to set the Plotter status and dependent status.
-
-        @param on flag indicating the active status
-        @type bool
-        """
-        pass
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return False, self.tr("Running scripts is not supported by this device.")
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pass
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return False, self.tr("File Manager is not supported by this device.")
-
-    def setFileManager(self, on):
-        """
-        Public method to set the File Manager status and dependent status.
-
-        @param on flag indicating the active status
-        @type bool
-        """
-        pass
-
-    def supportsLocalFileAccess(self):
-        """
-        Public method to indicate file access via a local directory.
-
-        @return flag indicating file access via local directory
-        @rtype bool
-        """
-        return False  # default
-
-    def getWorkspace(self):
-        """
-        Public method to get the workspace directory.
-
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        return (
-            Preferences.getMicroPython("MpyWorkspace")
-            or Preferences.getMultiProject("Workspace")
-            or os.path.expanduser("~")
-        )
-
-    def selectDeviceDirectory(self, deviceDirectories):
-        """
-        Public method to select the device directory from a list of detected
-        ones.
-
-        @param deviceDirectories list of directories to select from
-        @type list of str
-        @return selected directory or an empty string
-        @rtype str
-        """
-        deviceDirectory, ok = QInputDialog.getItem(
-            None,
-            self.tr("Select Device Directory"),
-            self.tr("Select the directory for the connected device:"),
-            [""] + deviceDirectories,
-            0,
-            False,
-        )
-        if ok:
-            return deviceDirectory
-        else:
-            # user cancelled
-            return ""
-
-    def sendCommands(self, commandsList):
-        """
-        Public method to send a list of commands to the device.
-
-        @param commandsList list of commands to be sent to the device
-        @type list of str
-        """
-        rawOn = [  # sequence of commands to enter raw mode
-            b"\x02",  # Ctrl-B: exit raw repl (just in case)
-            b"\r\x03\x03\x03",  # Ctrl-C three times: interrupt any running
-            # program
-            b"\r\x01",  # Ctrl-A: enter raw REPL
-        ]
-        newLine = [
-            b'print("\\n")\r',
-        ]
-        commands = [c.encode("utf-8)") + b"\r" for c in commandsList]
-        commands.append(b"\r")
-        commands.append(b"\x04")
-        rawOff = [b"\x02", b"\x02"]
-        commandSequence = rawOn + newLine + commands + rawOff
-        self.microPython.commandsInterface().executeAsync(commandSequence)
-
-    @pyqtSlot()
-    def handleDataFlood(self):
-        """
-        Public slot handling a data floof from the device.
-        """
-        pass
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        pass
-
-    def hasFlashMenuEntry(self):
-        """
-        Public method to check, if the device has its own flash menu entry.
-
-        @return flag indicating a specific flash menu entry
-        @rtype bool
-        """
-        return False
-
-    def hasTimeCommands(self):
-        """
-        Public method to check, if the device supports time commands.
-
-        The default returns True.
-
-        @return flag indicating support for time commands
-        @rtype bool
-        """
-        return True
-
-    def hasDocumentationUrl(self):
-        """
-        Public method to check, if the device has a configured documentation
-        URL.
-
-        @return flag indicating a configured documentation URL
-        @rtype bool
-        """
-        return bool(self.getDocumentationUrl())
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        return ""
-
-    def hasFirmwareUrl(self):
-        """
-        Public method to check, if the device has a configured firmware
-        download URL.
-
-        @return flag indicating a configured firmware download URL
-        @rtype bool
-        """
-        return bool(self.getFirmwareUrl())
-
-    def getFirmwareUrl(self):
-        """
-        Public method to get the device firmware download URL.
-
-        @return firmware download URL of the device
-        @rtype str
-        """
-        return ""
-
-    def downloadFirmware(self):
-        """
-        Public method to download the device firmware.
-        """
-        url = self.getFirmwareUrl()
-        if url:
-            ericApp().getObject("UserInterface").launchHelpViewer(url)
-
-    def getDownloadMenuEntries(self):
-        """
-        Public method to retrieve the entries for the downloads menu.
-
-        @return list of tuples with menu text and URL to be opened for each
-            entry
-        @rtype list of tuple of (str, str)
-        """
-        return []
--- a/src/eric7/MicroPython/MicrobitDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,653 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for BBC micro:bit and
-Calliope mini boards.
-"""
-
-import contextlib
-import os
-import shutil
-
-from PyQt6.QtCore import QStandardPaths, QUrl, pyqtSlot
-from PyQt6.QtNetwork import QNetworkRequest
-from PyQt6.QtWidgets import QInputDialog, QLineEdit, QMenu
-
-from eric7 import Globals, Preferences
-from eric7.EricWidgets import EricFileDialog, EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-from eric7.SystemUtilities import FileSystemUtilities
-
-from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class MicrobitDevice(MicroPythonDevice):
-    """
-    Class implementing the device for BBC micro:bit and Calliope mini boards.
-    """
-
-    def __init__(self, microPythonWidget, deviceType, serialNumber, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType type of the device
-        @type str
-        @param serialNumber serial number of the board
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__boardId = 0  # illegal ID
-        if serialNumber:
-            with contextlib.suppress(ValueError):
-                self.__boardId = int(serialNumber[:4], 16)
-
-        self.__createMicrobitMenu()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return True
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        if self.getDeviceType() == "bbc_microbit":
-            # BBC micro:bit
-            return self.tr("BBC micro:bit")
-        else:
-            # Calliope mini
-            return self.tr("Calliope mini")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def hasTimeCommands(self):
-        """
-        Public method to check, if the device supports time commands.
-
-        The default returns True.
-
-        @return flag indicating support for time commands
-        @rtype bool
-        """
-        if (
-            self.microPython.isConnected()
-            and self.checkDeviceData()
-            and self._deviceData["mpy_name"] == "circuitpython"
-        ):
-            return True
-
-        return False
-
-    def __isMicroBitV1(self):
-        """
-        Private method to check, if the device is a BBC micro:bit v1.
-
-        @return falg indicating a BBC micro:bit v1
-        @rtype bool
-        """
-        return self.__boardId in (0x9900, 0x9901)
-
-    def __isMicroBitV2(self):
-        """
-        Private method to check, if the device is a BBC micro:bit v2.
-
-        @return falg indicating a BBC micro:bit v2
-        @rtype bool
-        """
-        return self.__boardId in (0x9903, 0x9904, 0x9905, 0x9906)
-
-    def __isCalliope(self):
-        """
-        Private method to check, if the device is a Calliope mini.
-
-        @return flag indicating a Calliope mini
-        @rtype bool
-        """
-        return self.__boardId in (0x12A0,)
-
-    def __createMicrobitMenu(self):
-        """
-        Private method to create the microbit submenu.
-        """
-        self.__microbitMenu = QMenu(self.tr("BBC micro:bit/Calliope Functions"))
-
-        self.__showMpyAct = self.__microbitMenu.addAction(
-            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
-        )
-        self.__microbitMenu.addSeparator()
-        self.__flashMpyAct = self.__microbitMenu.addAction(
-            self.tr("Flash MicroPython"), self.__flashMicroPython
-        )
-        self.__flashDAPLinkAct = self.__microbitMenu.addAction(
-            self.tr("Flash Firmware"), lambda: self.__flashMicroPython(firmware=True)
-        )
-        self.__microbitMenu.addSeparator()
-        self.__saveScripAct = self.__microbitMenu.addAction(
-            self.tr("Save Script"), self.__saveScriptToDevice
-        )
-        self.__saveScripAct.setToolTip(
-            self.tr("Save the current script to the selected device")
-        )
-        self.__saveMainScriptAct = self.__microbitMenu.addAction(
-            self.tr("Save Script as 'main.py'"), self.__saveMain
-        )
-        self.__saveMainScriptAct.setToolTip(
-            self.tr("Save the current script as 'main.py' on the connected device")
-        )
-        self.__microbitMenu.addSeparator()
-        self.__resetAct = self.__microbitMenu.addAction(
-            self.tr("Reset {0}").format(self.deviceName()), self.__resetDevice
-        )
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        connected = self.microPython.isConnected()
-        linkConnected = self.microPython.isLinkConnected()
-
-        self.__showMpyAct.setEnabled(connected and self.getDeviceType() != "calliope")
-        self.__flashMpyAct.setEnabled(not linkConnected)
-        self.__flashDAPLinkAct.setEnabled(not linkConnected)
-        self.__saveScripAct.setEnabled(connected)
-        self.__saveMainScriptAct.setEnabled(connected)
-        self.__resetAct.setEnabled(connected)
-
-        menu.addMenu(self.__microbitMenu)
-
-    def hasFlashMenuEntry(self):
-        """
-        Public method to check, if the device has its own flash menu entry.
-
-        @return flag indicating a specific flash menu entry
-        @rtype bool
-        """
-        return True
-
-    @pyqtSlot()
-    def __flashMicroPython(self, firmware=False):
-        """
-        Private slot to flash MicroPython or the DAPLink firmware to the
-        device.
-
-        @param firmware flag indicating to flash the DAPLink firmware
-        @type bool
-        """
-        # Attempts to find the path on the file system that represents the
-        # plugged in micro:bit board. To flash the DAPLink firmware, it must be
-        # in maintenance mode, for MicroPython in standard mode.
-        if self.getDeviceType() == "bbc_microbit":
-            # BBC micro:bit
-            if firmware:
-                deviceDirectories = FileSystemUtilities.findVolume(
-                    "MAINTENANCE", findAll=True
-                )
-            else:
-                deviceDirectories = FileSystemUtilities.findVolume(
-                    "MICROBIT", findAll=True
-                )
-        else:
-            # Calliope mini
-            if firmware:
-                deviceDirectories = FileSystemUtilities.findVolume(
-                    "MAINTENANCE", findAll=True
-                )
-            else:
-                deviceDirectories = FileSystemUtilities.findVolume("MINI", findAll=True)
-        if len(deviceDirectories) == 0:
-            if self.getDeviceType() == "bbc_microbit":
-                # BBC micro:bit is not ready or not mounted
-                if firmware:
-                    EricMessageBox.critical(
-                        self.microPython,
-                        self.tr("Flash MicroPython/Firmware"),
-                        self.tr(
-                            "<p>The BBC micro:bit is not ready for flashing"
-                            " the DAPLink firmware. Follow these"
-                            " instructions. </p>"
-                            "<ul>"
-                            "<li>unplug USB cable and any batteries</li>"
-                            "<li>keep RESET button pressed and plug USB cable"
-                            " back in</li>"
-                            "<li>a drive called MAINTENANCE should be"
-                            " available</li>"
-                            "</ul>"
-                            "<p>See the "
-                            '<a href="https://microbit.org/guide/firmware/">'
-                            "micro:bit web site</a> for details.</p>"
-                        ),
-                    )
-                else:
-                    EricMessageBox.critical(
-                        self.microPython,
-                        self.tr("Flash MicroPython/Firmware"),
-                        self.tr(
-                            "<p>The BBC micro:bit is not ready for flashing"
-                            " the MicroPython firmware. Please make sure,"
-                            " that a drive called MICROBIT is available."
-                            "</p>"
-                        ),
-                    )
-            else:
-                # Calliope mini is not ready or not mounted
-                if firmware:
-                    EricMessageBox.critical(
-                        self.microPython,
-                        self.tr("Flash MicroPython/Firmware"),
-                        self.tr(
-                            '<p>The "Calliope mini" is not ready for flashing'
-                            " the DAPLink firmware. Follow these"
-                            " instructions. </p>"
-                            "<ul>"
-                            "<li>unplug USB cable and any batteries</li>"
-                            "<li>keep RESET button pressed an plug USB cable"
-                            " back in</li>"
-                            "<li>a drive called MAINTENANCE should be"
-                            " available</li>"
-                            "</ul>"
-                        ),
-                    )
-                else:
-                    EricMessageBox.critical(
-                        self.microPython,
-                        self.tr("Flash MicroPython/Firmware"),
-                        self.tr(
-                            '<p>The "Calliope mini" is not ready for flashing'
-                            " the MicroPython firmware. Please make sure,"
-                            " that a drive called MINI is available."
-                            "</p>"
-                        ),
-                    )
-        elif len(deviceDirectories) == 1:
-            downloadsPath = QStandardPaths.standardLocations(
-                QStandardPaths.StandardLocation.DownloadLocation
-            )[0]
-            firmware = EricFileDialog.getOpenFileName(
-                self.microPython,
-                self.tr("Flash MicroPython/Firmware"),
-                downloadsPath,
-                self.tr("MicroPython/Firmware Files (*.hex *.bin);;All Files (*)"),
-            )
-            if firmware and os.path.exists(firmware):
-                shutil.copy2(firmware, deviceDirectories[0])
-        else:
-            EricMessageBox.warning(
-                self,
-                self.tr("Flash MicroPython/Firmware"),
-                self.tr(
-                    "There are multiple devices ready for flashing."
-                    " Please make sure, that only one device is prepared."
-                ),
-            )
-
-    @pyqtSlot()
-    def __showFirmwareVersions(self):
-        """
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-        """
-        if self.microPython.isConnected() and self.checkDeviceData():
-            if self._deviceData["mpy_name"] not in ("micropython", "circuitpython"):
-                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"""
-                        """ or CircuitPython. Aborting..."""
-                    ),
-                )
-            else:
-                if self.getDeviceType() == "bbc_microbit":
-                    if self._deviceData["mpy_name"] == "micropython":
-                        if self.__isMicroBitV1():
-                            url = QUrl(FirmwareGithubUrls["microbit_v1"])
-                        elif self.__isMicroBitV2():
-                            url = QUrl(FirmwareGithubUrls["microbit_v2"])
-                        else:
-                            EricMessageBox.critical(
-                                None,
-                                self.tr("Show MicroPython Versions"),
-                                self.tr(
-                                    """<p>The BBC micro:bit generation cannot be"""
-                                    """ determined. Aborting...</p>"""
-                                ),
-                            )
-                            return
-                    elif self._deviceData["mpy_name"] == "circuitpython":
-                        url = QUrl(FirmwareGithubUrls["circuitpython"])
-                else:
-                    EricMessageBox.critical(
-                        None,
-                        self.tr("Show MicroPython Versions"),
-                        self.tr(
-                            """<p>The firmware URL for the device type <b>{0}</b>"""
-                            """ is not known. Aborting...</p>"""
-                        ).format(self.getDeviceType()),
-                    )
-                    return
-
-                ui = ericApp().getObject("UserInterface")
-                request = QNetworkRequest(url)
-                reply = ui.networkAccessManager().head(request)
-                reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
-
-    def __firmwareVersionResponse(self, reply):
-        """
-        Private method handling the response of the latest version request.
-
-        @param reply reference to the reply object
-        @type QNetworkReply
-        """
-        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 self._deviceData["release"] == "unknown":
-            currentVersionStr = self.tr("unknown")
-            currentVersion = (0, 0, 0)
-        else:
-            currentVersionStr = self._deviceData["release"]
-            currentVersion = Globals.versionToTuple(currentVersionStr)
-
-        if self._deviceData["mpy_name"] == "circuitpython":
-            kind = "CircuitPython"
-            microbitVersion = "2"  # only v2 device can run CircuitPython
-        elif self._deviceData["mpy_name"] == "micropython":
-            kind = "MicroPython"
-            if self.__isMicroBitV1():
-                microbitVersion = "1"
-            elif self.__isMicroBitV2():
-                microbitVersion = "2"
-        else:
-            kind = self.tr("Firmware")
-            microbitVersion = "?"
-
-        msg = self.tr(
-            "<h4>{0} Version Information<br/>"
-            "(BBC micro:bit v{1})</h4>"
-            "<table>"
-            "<tr><td>Installed:</td><td>{2}</td></tr>"
-            "<tr><td>Available:</td><td>{3}</td></tr>"
-            "</table>"
-        ).format(kind, microbitVersion, currentVersionStr, tag)
-        if currentVersion < latestVersion:
-            msg += self.tr("<p><b>Update available!</b></p>")
-
-        EricMessageBox.information(
-            None,
-            self.tr("{0} Version").format(kind),
-            msg,
-        )
-
-    @pyqtSlot()
-    def __saveMain(self):
-        """
-        Private slot to copy the current script as 'main.py' onto the
-        connected device.
-        """
-        self.__saveScriptToDevice("main.py")
-
-    @pyqtSlot()
-    def __saveScriptToDevice(self, scriptName=""):
-        """
-        Private method to save the current script onto the connected
-        device.
-
-        @param scriptName name of the file on the device
-        @type str
-        """
-        aw = ericApp().getObject("ViewManager").activeWindow()
-        if not aw:
-            return
-
-        title = (
-            self.tr("Save Script as '{0}'").format(scriptName)
-            if scriptName
-            else self.tr("Save Script")
-        )
-
-        if not (aw.isPyFile() or aw.isMicroPythonFile()):
-            yes = EricMessageBox.yesNo(
-                self.microPython,
-                title,
-                self.tr(
-                    """The current editor does not contain a Python"""
-                    """ script. Write it anyway?"""
-                ),
-            )
-            if not yes:
-                return
-
-        script = aw.text().strip()
-        if not script:
-            EricMessageBox.warning(
-                self.microPython, title, self.tr("""The script is empty. Aborting.""")
-            )
-            return
-
-        if not scriptName:
-            scriptName = os.path.basename(aw.getFileName())
-            scriptName, ok = QInputDialog.getText(
-                self.microPython,
-                title,
-                self.tr("Enter a file name on the device:"),
-                QLineEdit.EchoMode.Normal,
-                scriptName,
-            )
-            if not ok or not bool(scriptName):
-                return
-
-            title = self.tr("Save Script as '{0}'").format(scriptName)
-
-        commands = [
-            "fd = open('{0}', 'wb')".format(scriptName),
-            "f = fd.write",
-        ]
-        for line in script.splitlines():
-            commands.append("f(" + repr(line + "\n") + ")")
-        commands.append("fd.close()")
-        out, err = self.microPython.commandsInterface().execute(commands)
-        if err:
-            EricMessageBox.critical(
-                self.microPython,
-                title,
-                self.tr(
-                    """<p>The script could not be saved to the"""
-                    """ device.</p><p>Reason: {0}</p>"""
-                ).format(err.decode("utf-8")),
-            )
-
-        # reset the device
-        self.__resetDevice()
-
-    @pyqtSlot()
-    def __resetDevice(self):
-        """
-        Private slot to reset the connected device.
-        """
-        if self.getDeviceType() == "bbc_microbit":
-            # BBC micro:bit
-            self.microPython.commandsInterface().execute(
-                [
-                    "import microbit",
-                    "microbit.reset()",
-                ]
-            )
-        else:
-            # Calliope mini
-            self.microPython.commandsInterface().execute(
-                [
-                    "import calliope_mini",
-                    "calliope_mini.reset()",
-                ]
-            )
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        if self.getDeviceType() == "bbc_microbit":
-            # BBC micro:bit
-            if self._deviceData and self._deviceData["mpy_name"] == "circuitpython":
-                return Preferences.getMicroPython("CircuitPythonDocuUrl")
-            else:
-                return Preferences.getMicroPython("MicrobitDocuUrl")
-        else:
-            # Calliope mini
-            return Preferences.getMicroPython("CalliopeDocuUrl")
-
-    def getDownloadMenuEntries(self):
-        """
-        Public method to retrieve the entries for the downloads menu.
-
-        @return list of tuples with menu text and URL to be opened for each
-            entry
-        @rtype list of tuple of (str, str)
-        """
-        if self.getDeviceType() == "bbc_microbit":
-            if self.__isMicroBitV1():
-                return [
-                    (
-                        self.tr("MicroPython Firmware for BBC micro:bit V1"),
-                        Preferences.getMicroPython("MicrobitMicroPythonUrl"),
-                    ),
-                    (
-                        self.tr("DAPLink Firmware"),
-                        Preferences.getMicroPython("MicrobitFirmwareUrl"),
-                    ),
-                ]
-            elif self.__isMicroBitV2():
-                return [
-                    (
-                        self.tr("MicroPython Firmware for BBC micro:bit V2"),
-                        Preferences.getMicroPython("MicrobitV2MicroPythonUrl"),
-                    ),
-                    (
-                        self.tr("CircuitPython Firmware for BBC micro:bit V2"),
-                        "https://circuitpython.org/board/microbit_v2/",
-                    ),
-                    (
-                        self.tr("DAPLink Firmware"),
-                        Preferences.getMicroPython("MicrobitFirmwareUrl"),
-                    ),
-                ]
-            else:
-                return []
-        else:
-            return [
-                (
-                    self.tr("MicroPython Firmware"),
-                    Preferences.getMicroPython("CalliopeMicroPythonUrl"),
-                ),
-                (
-                    self.tr("DAPLink Firmware"),
-                    Preferences.getMicroPython("CalliopeDAPLinkUrl"),
-                ),
-            ]
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype MicrobitDevice
-    """
-    return MicrobitDevice(microPythonWidget, deviceType, serialNumber)
--- a/src/eric7/MicroPython/PyBoardDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,522 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2019 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for PyBoard boards.
-"""
-
-import os
-
-from PyQt6.QtCore import QStandardPaths, QUrl, pyqtSlot
-from PyQt6.QtNetwork import QNetworkRequest
-from PyQt6.QtWidgets import QMenu
-
-from eric7 import Globals, Preferences
-from eric7.EricWidgets import EricFileDialog, EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-from eric7.EricWidgets.EricProcessDialog import EricProcessDialog
-from eric7.SystemUtilities import FileSystemUtilities
-
-from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class PyBoardDevice(MicroPythonDevice):
-    """
-    Class implementing the device for PyBoard boards.
-    """
-
-    DeviceVolumeName = "PYBFLASH"
-
-    FlashInstructionsURL = (
-        "https://github.com/micropython/micropython/wiki/Pyboard-Firmware-Update"
-    )
-
-    def __init__(self, microPythonWidget, deviceType, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__workspace = self.__findWorkspace()
-
-        self.__createPyboardMenu()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-        if self.__deviceVolumeMounted():
-            self.microPython.setActionButtons(open=True, save=True)
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return False
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.tr("PyBoard")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def supportsLocalFileAccess(self):
-        """
-        Public method to indicate file access via a local directory.
-
-        @return flag indicating file access via local directory
-        @rtype bool
-        """
-        return self.__deviceVolumeMounted()
-
-    def __deviceVolumeMounted(self):
-        """
-        Private method to check, if the device volume is mounted.
-
-        @return flag indicated a mounted device
-        @rtype bool
-        """
-        if self.__workspace and not os.path.exists(self.__workspace):
-            self.__workspace = ""  # reset
-
-        return self.DeviceVolumeName in self.getWorkspace(silent=True)
-
-    def getWorkspace(self, silent=False):
-        """
-        Public method to get the workspace directory.
-
-        @param silent flag indicating silent operations
-        @type bool
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        if self.__workspace:
-            # return cached entry
-            return self.__workspace
-        else:
-            self.__workspace = self.__findWorkspace(silent=silent)
-            return self.__workspace
-
-    def __findWorkspace(self, silent=False):
-        """
-        Private method to find the workspace directory.
-
-        @param silent flag indicating silent operations
-        @type bool
-        @return workspace directory used for saving files
-        @rtype str
-        """
-        # Attempts to find the path on the filesystem that represents the
-        # plugged in PyBoard board.
-        deviceDirectories = FileSystemUtilities.findVolume(
-            self.DeviceVolumeName, findAll=True
-        )
-
-        if deviceDirectories:
-            if len(deviceDirectories) == 1:
-                return deviceDirectories[0]
-            else:
-                return self.selectDeviceDirectory(deviceDirectories)
-        else:
-            # return the default workspace and give the user a warning (unless
-            # silent mode is selected)
-            if not silent:
-                EricMessageBox.warning(
-                    self.microPython,
-                    self.tr("Workspace Directory"),
-                    self.tr(
-                        "Python files for PyBoard can be edited in"
-                        " place, if the device volume is locally"
-                        " available. Such a volume was not found. In"
-                        " place editing will not be available."
-                    ),
-                )
-
-            return super().getWorkspace()
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonDocuUrl")
-
-    def getFirmwareUrl(self):
-        """
-        Public method to get the device firmware download URL.
-
-        @return firmware download URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonFirmwareUrl")
-
-    def __createPyboardMenu(self):
-        """
-        Private method to create the pyboard submenu.
-        """
-        self.__pyboardMenu = QMenu(self.tr("PyBoard Functions"))
-
-        self.__showMpyAct = self.__pyboardMenu.addAction(
-            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
-        )
-        self.__pyboardMenu.addSeparator()
-        self.__bootloaderAct = self.__pyboardMenu.addAction(
-            self.tr("Activate Bootloader"), self.__activateBootloader
-        )
-        self.__dfuAct = self.__pyboardMenu.addAction(
-            self.tr("List DFU-capable Devices"), self.__listDfuCapableDevices
-        )
-        self.__pyboardMenu.addSeparator()
-        self.__flashMpyAct = self.__pyboardMenu.addAction(
-            self.tr("Flash MicroPython Firmware"), self.__flashMicroPython
-        )
-        self.__pyboardMenu.addAction(
-            self.tr("MicroPython Flash Instructions"), self.__showFlashInstructions
-        )
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        connected = self.microPython.isConnected()
-        linkConnected = self.microPython.isLinkConnected()
-
-        self.__bootloaderAct.setEnabled(connected)
-        self.__dfuAct.setEnabled(not linkConnected)
-        self.__showMpyAct.setEnabled(connected)
-        self.__flashMpyAct.setEnabled(not linkConnected)
-
-        menu.addMenu(self.__pyboardMenu)
-
-    def hasFlashMenuEntry(self):
-        """
-        Public method to check, if the device has its own flash menu entry.
-
-        @return flag indicating a specific flash menu entry
-        @rtype bool
-        """
-        return True
-
-    @pyqtSlot()
-    def __showFlashInstructions(self):
-        """
-        Private slot to open the URL containing instructions for installing
-        MicroPython on the pyboard.
-        """
-        ericApp().getObject("UserInterface").launchHelpViewer(
-            PyBoardDevice.FlashInstructionsURL
-        )
-
-    def __dfuUtilAvailable(self):
-        """
-        Private method to check the availability of dfu-util.
-
-        @return flag indicating the availability of dfu-util
-        @rtype bool
-        """
-        available = False
-        program = Preferences.getMicroPython("DfuUtilPath")
-        if not program:
-            program = "dfu-util"
-            if FileSystemUtilities.isinpath(program):
-                available = True
-        else:
-            if FileSystemUtilities.isExecutable(program):
-                available = True
-
-        if not available:
-            EricMessageBox.critical(
-                self.microPython,
-                self.tr("dfu-util not available"),
-                self.tr(
-                    """The dfu-util firmware flashing tool"""
-                    """ <b>dfu-util</b> cannot be found or is not"""
-                    """ executable. Ensure it is in the search path"""
-                    """ or configure it on the MicroPython"""
-                    """ configuration page."""
-                ),
-            )
-
-        return available
-
-    def __showDfuEnableInstructions(self, flash=True):
-        """
-        Private method to show some instructions to enable the DFU mode.
-
-        @param flash flag indicating to show a warning message for flashing
-        @type bool
-        @return flag indicating OK to continue or abort
-        @rtype bool
-        """
-        msg = self.tr(
-            "<h3>Enable DFU Mode</h3>"
-            "<p>1. Disconnect everything from your board</p>"
-            "<p>2. Disconnect your board</p>"
-            "<p>3. Connect the DFU/BOOT0 pin with a 3.3V pin</p>"
-            "<p>4. Re-connect your board</p>"
-            "<hr />"
-        )
-
-        if flash:
-            msg += self.tr(
-                "<p><b>Warning:</b> Make sure that all other DFU capable"
-                " devices except your PyBoard are disconnected."
-                "<hr />"
-            )
-
-        msg += self.tr("<p>Press <b>OK</b> to continue...</p>")
-        res = EricMessageBox.information(
-            self.microPython,
-            self.tr("Enable DFU mode"),
-            msg,
-            EricMessageBox.Abort | EricMessageBox.Ok,
-        )
-
-        return res == EricMessageBox.Ok
-
-    def __showDfuDisableInstructions(self):
-        """
-        Private method to show some instructions to disable the DFU mode.
-        """
-        msg = self.tr(
-            "<h3>Disable DFU Mode</h3>"
-            "<p>1. Disconnect your board</p>"
-            "<p>2. Remove the DFU jumper</p>"
-            "<p>3. Re-connect your board</p>"
-            "<hr />"
-            "<p>Press <b>OK</b> to continue...</p>"
-        )
-        EricMessageBox.information(self.microPython, self.tr("Disable DFU mode"), msg)
-
-    @pyqtSlot()
-    def __listDfuCapableDevices(self):
-        """
-        Private slot to list all DFU-capable devices.
-        """
-        if self.__dfuUtilAvailable():
-            ok2continue = self.__showDfuEnableInstructions(flash=False)
-            if ok2continue:
-                program = Preferences.getMicroPython("DfuUtilPath")
-                if not program:
-                    program = "dfu-util"
-
-                args = [
-                    "--list",
-                ]
-                dlg = EricProcessDialog(
-                    self.tr("'dfu-util' Output"), self.tr("List DFU capable Devices")
-                )
-                res = dlg.startProcess(program, args)
-                if res:
-                    dlg.exec()
-
-    @pyqtSlot()
-    def __flashMicroPython(self):
-        """
-        Private slot to flash a MicroPython firmware.
-        """
-        if self.__dfuUtilAvailable():
-            ok2continue = self.__showDfuEnableInstructions()
-            if ok2continue:
-                program = Preferences.getMicroPython("DfuUtilPath")
-                if not program:
-                    program = "dfu-util"
-
-                downloadsPath = QStandardPaths.standardLocations(
-                    QStandardPaths.StandardLocation.DownloadLocation
-                )[0]
-                firmware = EricFileDialog.getOpenFileName(
-                    self.microPython,
-                    self.tr("Flash MicroPython Firmware"),
-                    downloadsPath,
-                    self.tr("MicroPython Firmware Files (*.dfu);;All Files (*)"),
-                )
-                if firmware and os.path.exists(firmware):
-                    args = [
-                        "--alt",
-                        "0",
-                        "--download",
-                        firmware,
-                    ]
-                    dlg = EricProcessDialog(
-                        self.tr("'dfu-util' Output"),
-                        self.tr("Flash MicroPython Firmware"),
-                    )
-                    res = dlg.startProcess(program, args)
-                    if res:
-                        dlg.exec()
-                        self.__showDfuDisableInstructions()
-
-    @pyqtSlot()
-    def __showFirmwareVersions(self):
-        """
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-        """
-        if self.microPython.isConnected():
-            if self._deviceData["mpy_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))
-
-    def __firmwareVersionResponse(self, reply):
-        """
-        Private method handling the response of the latest version request.
-
-        @param reply reference to the reply object
-        @type QNetworkReply
-        """
-        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 self._deviceData["mpy_version"] == "unknown":
-            currentVersionStr = self.tr("unknown")
-            currentVersion = (0, 0, 0)
-        else:
-            currentVersionStr = self._deviceData["mpy_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 __activateBootloader(self):
-        """
-        Private slot to activate the bootloader and disconnect.
-        """
-        if self.microPython.isConnected():
-            self.microPython.commandsInterface().execute(
-                [
-                    "import pyb",
-                    "pyb.bootloader()",
-                ]
-            )
-            # simulate pressing the disconnect button
-            self.microPython.on_connectButton_clicked()
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype PyBoardDevice
-    """
-    return PyBoardDevice(microPythonWidget, deviceType)
--- a/src/eric7/MicroPython/RP2040Devices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,317 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2021 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for RP2040 based boards
-(e.g. Raspberry Pi Pico).
-"""
-
-from PyQt6.QtCore import QUrl, pyqtSlot
-from PyQt6.QtNetwork import QNetworkRequest
-from PyQt6.QtWidgets import QMenu
-
-from eric7 import Globals, Preferences
-from eric7.EricWidgets import EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-
-from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class RP2040Device(MicroPythonDevice):
-    """
-    Class implementing the device for RP2040 based boards.
-    """
-
-    def __init__(self, microPythonWidget, deviceType, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__createRP2040Menu()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return False
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.tr("RP2040")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def __createRP2040Menu(self):
-        """
-        Private method to create the RO2040 submenu.
-        """
-        self.__rp2040Menu = QMenu(self.tr("RP2040 Functions"))
-
-        self.__showMpyAct = self.__rp2040Menu.addAction(
-            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
-        )
-        self.__rp2040Menu.addSeparator()
-        self.__bootloaderAct = self.__rp2040Menu.addAction(
-            self.tr("Activate Bootloader"), self.__activateBootloader
-        )
-        self.__flashMpyAct = self.__rp2040Menu.addAction(
-            self.tr("Flash MicroPython Firmware"), self.__flashPython
-        )
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        connected = self.microPython.isConnected()
-        linkConnected = self.microPython.isLinkConnected()
-
-        self.__showMpyAct.setEnabled(connected)
-        self.__bootloaderAct.setEnabled(connected)
-        self.__flashMpyAct.setEnabled(not linkConnected)
-
-        menu.addMenu(self.__rp2040Menu)
-
-    def hasFlashMenuEntry(self):
-        """
-        Public method to check, if the device has its own flash menu entry.
-
-        @return flag indicating a specific flash menu entry
-        @rtype bool
-        """
-        return True
-
-    @pyqtSlot()
-    def __flashPython(self):
-        """
-        Private slot to flash a MicroPython firmware to the device.
-        """
-        from .UF2FlashDialog import UF2FlashDialog
-
-        dlg = UF2FlashDialog(boardType="rp2040")
-        dlg.exec()
-
-    def __activateBootloader(self):
-        """
-        Private method to switch the board into 'bootloader' mode.
-        """
-        if self.microPython.isConnected():
-            self.microPython.commandsInterface().execute(
-                [
-                    "import machine",
-                    "machine.bootloader()",
-                ]
-            )
-            # simulate pressing the disconnect button
-            self.microPython.on_connectButton_clicked()
-
-    @pyqtSlot()
-    def __showFirmwareVersions(self):
-        """
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-        """
-        if self.microPython.isConnected():
-            if self._deviceData["mpy_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:
-                if self._deviceData["mpy_variant"] == "Pimoroni":
-                    # MicroPython with Pimoroni add-on libraries
-                    url = QUrl(FirmwareGithubUrls["pimoroni_pico"])
-                else:
-                    url = QUrl(FirmwareGithubUrls["micropython"])
-                ui = ericApp().getObject("UserInterface")
-                request = QNetworkRequest(url)
-                reply = ui.networkAccessManager().head(request)
-                reply.finished.connect(lambda: self.__firmwareVersionResponse(reply))
-
-    def __firmwareVersionResponse(self, reply):
-        """
-        Private method handling the response of the latest version request.
-
-        @param reply reference to the reply object
-        @type QNetworkReply
-        """
-        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 self._deviceData["mpy_version"] == "unknown":
-            currentVersionStr = self.tr("unknown")
-            currentVersion = (0, 0, 0)
-        else:
-            currentVersionStr = self._deviceData["mpy_version"]
-            currentVersion = Globals.versionToTuple(currentVersionStr)
-
-        msg = self.tr(
-            "<h4>MicroPython Version Information</h4>"
-            "<table>"
-            "<tr><td>Installed:</td><td>{0}</td><td></td></tr>"
-            "<tr><td>Available:</td><td>{1}</td><td>{2}</td></tr>"
-            "</table>"
-        ).format(
-            currentVersionStr,
-            tag,
-            self.tr("({0})").format(self._deviceData["mpy_variant"])
-            if self._deviceData["mpy_variant"]
-            else "",
-        )
-        if (
-            self._deviceData["mpy_variant"] not in ["Pimoroni"]
-            and currentVersion < latestVersion
-        ):
-            # cannot derive that info for 'Pimoroni' variant
-            msg += self.tr("<p><b>Update available!</b></p>")
-
-        EricMessageBox.information(
-            None,
-            self.tr("MicroPython Version"),
-            msg,
-        )
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonDocuUrl")
-
-    def getDownloadMenuEntries(self):
-        """
-        Public method to retrieve the entries for the downloads menu.
-
-        @return list of tuples with menu text and URL to be opened for each
-            entry
-        @rtype list of tuple of (str, str)
-        """
-        return [
-            (
-                self.tr("MicroPython Firmware"),
-                Preferences.getMicroPython("MicroPythonFirmwareUrl"),
-            ),
-            ("<separator>", ""),
-            (self.tr("Pimoroni Pico Firmware"), FirmwareGithubUrls["pimoroni_pico"]),
-            ("<separator>", ""),
-            (
-                self.tr("CircuitPython Firmware"),
-                Preferences.getMicroPython("CircuitPythonFirmwareUrl"),
-            ),
-            (
-                self.tr("CircuitPython Libraries"),
-                Preferences.getMicroPython("CircuitPythonLibrariesUrl"),
-            ),
-        ]
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype RP2040Device
-    """
-    return RP2040Device(microPythonWidget, deviceType)
--- a/src/eric7/MicroPython/TeensyDevices.py	Sun Feb 12 18:11:20 2023 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,287 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
-#
-
-"""
-Module implementing the device interface class for Teensy boards with MicroPython.
-"""
-
-from PyQt6.QtCore import QProcess, QUrl, pyqtSlot
-from PyQt6.QtNetwork import QNetworkRequest
-from PyQt6.QtWidgets import QMenu
-
-from eric7 import Globals, Preferences
-from eric7.EricWidgets import EricMessageBox
-from eric7.EricWidgets.EricApplication import ericApp
-
-from .MicroPythonDevices import FirmwareGithubUrls, MicroPythonDevice
-from .MicroPythonWidget import HAS_QTCHART
-
-
-class TeensyDevice(MicroPythonDevice):
-    """
-    Class implementing the device for Teensy boards with MicroPython.
-    """
-
-    def __init__(self, microPythonWidget, deviceType, parent=None):
-        """
-        Constructor
-
-        @param microPythonWidget reference to the main MicroPython widget
-        @type MicroPythonWidget
-        @param deviceType device type assigned to this device interface
-        @type str
-        @param parent reference to the parent object
-        @type QObject
-        """
-        super().__init__(microPythonWidget, deviceType, parent)
-
-        self.__createTeensyMenu()
-
-    def setButtons(self):
-        """
-        Public method to enable the supported action buttons.
-        """
-        super().setButtons()
-        self.microPython.setActionButtons(
-            run=True, repl=True, files=True, chart=HAS_QTCHART
-        )
-
-    def forceInterrupt(self):
-        """
-        Public method to determine the need for an interrupt when opening the
-        serial connection.
-
-        @return flag indicating an interrupt is needed
-        @rtype bool
-        """
-        return False
-
-    def deviceName(self):
-        """
-        Public method to get the name of the device.
-
-        @return name of the device
-        @rtype str
-        """
-        return self.tr("Teensy")
-
-    def canStartRepl(self):
-        """
-        Public method to determine, if a REPL can be started.
-
-        @return tuple containing a flag indicating it is safe to start a REPL
-            and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canStartPlotter(self):
-        """
-        Public method to determine, if a Plotter can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def canRunScript(self):
-        """
-        Public method to determine, if a script can be executed.
-
-        @return tuple containing a flag indicating it is safe to start a
-            Plotter and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def runScript(self, script):
-        """
-        Public method to run the given Python script.
-
-        @param script script to be executed
-        @type str
-        """
-        pythonScript = script.split("\n")
-        self.sendCommands(pythonScript)
-
-    def canStartFileManager(self):
-        """
-        Public method to determine, if a File Manager can be started.
-
-        @return tuple containing a flag indicating it is safe to start a
-            File Manager and a reason why it cannot.
-        @rtype tuple of (bool, str)
-        """
-        return True, ""
-
-    def getDocumentationUrl(self):
-        """
-        Public method to get the device documentation URL.
-
-        @return documentation URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonDocuUrl")
-
-    def getFirmwareUrl(self):
-        """
-        Public method to get the device firmware download URL.
-
-        @return firmware download URL of the device
-        @rtype str
-        """
-        return Preferences.getMicroPython("MicroPythonFirmwareUrl")
-
-    def __createTeensyMenu(self):
-        """
-        Private method to create the microbit submenu.
-        """
-        self.__teensyMenu = QMenu(self.tr("Teensy Functions"))
-
-        self.__showMpyAct = self.__teensyMenu.addAction(
-            self.tr("Show MicroPython Versions"), self.__showFirmwareVersions
-        )
-        self.__teensyMenu.addSeparator()
-        self.__teensyMenu.addAction(
-            self.tr("MicroPython Flash Instructions"), self.__showFlashInstructions
-        )
-        self.__flashMpyAct = self.__teensyMenu.addAction(
-            self.tr("Flash MicroPython Firmware"), self.__startTeensyLoader
-        )
-        self.__flashMpyAct.setToolTip(
-            self.tr("Start the 'Teensy Loader' application to flash the Teensy device.")
-        )
-
-    def addDeviceMenuEntries(self, menu):
-        """
-        Public method to add device specific entries to the given menu.
-
-        @param menu reference to the context menu
-        @type QMenu
-        """
-        connected = self.microPython.isConnected()
-        linkConnected = self.microPython.isLinkConnected()
-
-        self.__showMpyAct.setEnabled(connected)
-        self.__flashMpyAct.setEnabled(not linkConnected)
-
-        menu.addMenu(self.__teensyMenu)
-
-    @pyqtSlot()
-    def __showFirmwareVersions(self):
-        """
-        Private slot to show the firmware version of the connected device and the
-        available firmware version.
-        """
-        if self.microPython.isConnected():
-            if self._deviceData["mpy_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))
-
-    def __firmwareVersionResponse(self, reply):
-        """
-        Private method handling the response of the latest version request.
-
-        @param reply reference to the reply object
-        @type QNetworkReply
-        """
-        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 self._deviceData["mpy_version"] == "unknown":
-            currentVersionStr = self.tr("unknown")
-            currentVersion = (0, 0, 0)
-        else:
-            currentVersionStr = self._deviceData["mpy_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,
-        )
-
-    def __showFlashInstructions(self):
-        """
-        Private method to show a message box with instruction to flash the Teensy.
-        """
-        EricMessageBox.information(
-            self.microPython,
-            self.tr("Flash MicroPython Firmware"),
-            self.tr(
-                """<p>Teensy 4.0 and Teensy 4.1 are flashed using the 'Teensy Loader'"""
-                """ application. Make sure you downloaded the MicroPython or"""
-                """ CircuitPython .hex file.</p>"""
-                """<p>See <a href="{0}">the PJRC Teensy web site</a>"""
-                """ for details.</p>"""
-            ).format("https://www.pjrc.com/teensy/loader.html"),
-        )
-
-    def __startTeensyLoader(self):
-        """
-        Private method to start the 'Teensy Loader' application.
-
-        Note: The application must be accessible via the application search path.
-        """
-        ok, _ = QProcess.startDetached("teensy")
-        if not ok:
-            EricMessageBox.warning(
-                self.microPython,
-                self.tr("Start 'Teensy Loader'"),
-                self.tr(
-                    """<p>The 'Teensy Loader' application <b>teensy</b> could not"""
-                    """ be started. Ensure it is in the application search path or"""
-                    """ start it manually.</p>"""
-                ),
-            )
-
-
-def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):
-    """
-    Function to instantiate a MicroPython device object.
-
-    @param microPythonWidget reference to the main MicroPython widget
-    @type MicroPythonWidget
-    @param deviceType device type assigned to this device interface
-    @type str
-    @param vid vendor ID
-    @type int
-    @param pid product ID
-    @type int
-    @param boardName name of the board
-    @type str
-    @param serialNumber serial number of the board
-    @type str
-    @return reference to the instantiated device object
-    @rtype PyBoardDevice
-    """
-    return TeensyDevice(microPythonWidget, deviceType)

eric ide

mercurial