MicroPython eric7 tip

Fri, 25 Apr 2025 16:23:02 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 25 Apr 2025 16:23:02 +0200
branch
eric7
changeset 11236
75c26fe1d1c7
parent 11235
b984f0085bed

MicroPython
- Extended the handling of Access Point security/authmode settings to be more dynamic.

src/eric7/MicroPython/Devices/CircuitPythonDevices.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/RP2Devices.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/WifiDialogs/WifiController.py file | annotate | diff | comparison | revisions
src/eric7/MicroPython/WifiDialogs/WifiStatusDialog.py file | annotate | diff | comparison | revisions
src/eric7/Preferences/__init__.py file | annotate | diff | comparison | revisions
--- a/src/eric7/MicroPython/Devices/CircuitPythonDevices.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/Devices/CircuitPythonDevices.py	Fri Apr 25 16:23:02 2025 +0200
@@ -98,16 +98,20 @@
             "WPA3_PSK": "WPA3",
             "WPA2_WPA3_PSK": "WPA2/WPA3",
         }
+
         self.__securityCode2AuthModeString = {
-            0: "[wifi.AuthMode.OPEN]",
-            1: "[wifi.AuthMode.WEP]",
-            2: "[wifi.AuthMode.WPA, wifi.AuthMode.PSK]",
-            3: "[wifi.AuthMode.WPA2, wifi.AuthMode.PSK]",
-            4: "[wifi.AuthMode.WPA, wifi.AuthMode.WPA2, wifi.AuthMode.PSK]",
-            5: "[wifi.AuthMode.WPA2, wifi.AuthMode.ENTERPRISE]",
-            6: "[wifi.AuthMode.WPA3, wifi.AuthMode.PSK]",
-            7: "[wifi.AuthMode.WPA2, wifi.AuthMode.WPA3, wifi.AuthMode.PSK]",
+            "SEC_OPEN": "[wifi.AuthMode.OPEN]",
+            "SEC_WEP": "[wifi.AuthMode.WEP]",
+            "SEC_WPA": "[wifi.AuthMode.WPA, wifi.AuthMode.PSK]",
+            "SEC_WPA2": "[wifi.AuthMode.WPA2, wifi.AuthMode.PSK]",
+            "SEC_WPA_WPA2": "[wifi.AuthMode.WPA, wifi.AuthMode.WPA2, wifi.AuthMode.PSK]",
+            # noqa: E-501
+            "SEC_WPA2_ENT": "[wifi.AuthMode.WPA2, wifi.AuthMode.ENTERPRISE]",
+            "SEC_WPA3": "[wifi.AuthMode.WPA3, wifi.AuthMode.PSK]",
+            "SEC_WPA2_WPA3": "[wifi.AuthMode.WPA2, wifi.AuthMode.WPA3, wifi.AuthMode.PSK]",
+            # noqa: E-501
         }
+
         self.__bleAddressType = {
             0: self.tr("Public"),
             1: self.tr("Random Static"),
@@ -1237,8 +1241,8 @@
 
         @param ssid SSID of the access point
         @type str
-        @param security security method (defaults to None)
-        @type int (optional)
+        @param security security mode (defaults to None) (unused)
+        @type str (optional)
         @param password password (defaults to None)
         @type str (optional)
         @param hostname host name of the device (defaults to None)
@@ -1250,7 +1254,7 @@
         @rtype tuple of (bool, str)
         """
         if security is None or password is None:
-            security = 0
+            security = "SEC_OPEN"
             password = ""  # secok
         authmode = self.__securityCode2AuthModeString[security]
 
@@ -1332,6 +1336,15 @@
             self.tr("CircuitPython does not support reporting of connected clients."),
         )
 
+    def getSecurityModes(self):
+        """
+        Public method to get a list of security modes supported by the device.
+
+        @return list of supported security modes
+        @rtype list of str
+        """
+        return list(self.__securityCode2AuthModeString.keys())
+
     ##################################################################
     ## Methods below implement Ethernet related methods
     ##################################################################
--- a/src/eric7/MicroPython/Devices/DeviceBase.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/Devices/DeviceBase.py	Fri Apr 25 16:23:02 2025 +0200
@@ -82,6 +82,9 @@
     <li>startAccessPoint: start an access point</li>
     <li>stopAccessPoint: stop the access point</li>
     <li>getConnectedClients: get a list of connected WiFi clients</li>
+    <li>getSecurityModes: get a list of supported security modes</li>
+    <li>enableWebrepl
+    <li>disableWebrepl
     </ul>
 
     Supported Bluetooth commands are:
@@ -1911,8 +1914,8 @@
 
         @param ssid SSID of the access point (unused)
         @type str
-        @param security security method (defaults to None) (unused)
-        @type int (optional)
+        @param security security mode (defaults to None) (unused)
+        @type str (optional)
         @param password password (defaults to None) (unused)
         @type str (optional)
         @param hostname host name of the device (defaults to None) (unused)
@@ -1944,6 +1947,28 @@
         """
         return [], ""
 
+    def getSecurityModes(self):
+        """
+        Public method to get a list of security modes supported by the device.
+
+        @return list of supported security modes
+        @rtype list of str
+        """
+        command = """
+def getSecurityModes():
+    import network
+    modes = [s for s in dir(network.WLAN) if s.startswith('SEC_')]
+    return modes
+
+print(getSecurityModes())
+del getSecurityModes
+"""
+        out, err = self.executeCommands(command, mode=self._submitMode)
+        if err:
+            return []
+
+        return ast.literal_eval(out.decode("utf-8"))
+
     def enableWebrepl(self, password):  # noqa: U-100
         """
         Public method to write the given WebREPL password to the connected device and
@@ -1958,8 +1983,7 @@
 
     def disableWebrepl(self):
         """
-        Public method to write the given WebREPL password to the connected device and
-        modify the start script to start the WebREPL server.
+        Public method to modify the start script to not start the WebREPL server.
 
         @return tuple containing a flag indicating success and an error message
         @rtype tuple of (bool, str)
--- a/src/eric7/MicroPython/Devices/EspDevices.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/Devices/EspDevices.py	Fri Apr 25 16:23:02 2025 +0200
@@ -76,6 +76,24 @@
             6: "WPA3",
             7: "WPA2/WPA3",
         }
+        self.__securityMapping = {
+            "SEC_DPP": "DPP",
+            "SEC_OPEN": self.tr("Open"),
+            "SEC_OWE": "OWE",
+            "SEC_WAPI": "WAPI",
+            "SEC_WEP": "WEP",
+            "SEC_WPA": "WPA",
+            "SEC_WPA_WPA2": "WPA/WPA2",
+            "SEC_WPA2": "WPA2",
+            "SEC_WPA2_ENT": "WPA2 Enterprise",
+            "SEC_WPA2_WPA3": "WPA2/WPA3",
+            "SEC_WPA2_WPA3_ENT": "WPA2/WPA3 Enterprise",
+            "SEC_WPA3": "WPA3",
+            "SEC_WPA3_ENT": "WPA3 Enterprise",
+            "SEC_WPA3_ENT_192": "WPA3 Enterprise (192-bit)",
+            "SEC_WPA3_EXT_PSK": "WPA3 Extended",
+            "SEC_WPA3_EXT_PSK_MIXED_MODE": "WPA3 Extended, Mixed Mode",
+        }
 
     def __createCpyDevice(self):
         """
@@ -718,6 +736,12 @@
     import ujson
     import network
 
+    def security_str(mode):
+        for sm in [e for e in dir(network.WLAN) if e.startswith('SEC_')]:
+            if getattr(network.WLAN, sm, 0) == mode:
+                return sm
+        return ""
+
     wifi = network.WLAN(network.STA_IF)
     station = {
         'active': wifi.active(),
@@ -742,6 +766,7 @@
         'mac': ubinascii.hexlify(wifi.config('mac'), ':').decode(),
         'channel': wifi.config('channel'),
         'essid': wifi.config('essid'),
+        'ap_security': security_str(wifi.config('security')),
     }
     if wifi.active():
         try:
@@ -783,6 +808,11 @@
             ap["status"] = self.__statusTranslations[ap["status"]]
         except KeyError:
             ap["status"] = str(ap["status"])
+        if "ap_security" in ap:
+            try:
+                ap["ap_security"] = self.__securityMapping[ap["ap_security"]]
+            except KeyError:
+                ap["ap_security"] = self.tr("unknown ({0})").format(ap["ap_security"])
         return station, ap, overall
 
     def connectWifi(self, ssid, password, hostname):
@@ -1188,8 +1218,8 @@
 
         @param ssid SSID of the access point
         @type str
-        @param security security method (defaults to None)
-        @type int (optional)
+        @param security security mode (defaults to None) (unused)
+        @type str (optional)
         @param password password (defaults to None)
         @type str (optional)
         @param hostname host name of the device (defaults to None)
@@ -1210,13 +1240,11 @@
             )
 
         if security is None or password is None:
-            security = 0
+            security = "SEC_OPEN"
             password = ""  # secok
-        if security > 4:
-            security = 4  # security >4 cause an error thrown by the ESP32
 
         command = """
-def start_ap(ssid, authmode, password, hostname, ifconfig):
+def start_ap(ssid, password, hostname, ifconfig):
     import network
 
     if hostname:
@@ -1231,14 +1259,14 @@
         ap.ifconfig(ifconfig)
     ap.active(True)
     try:
-        ap.config(ssid=ssid, authmode=authmode, password=password)
+        ap.config(ssid=ssid, authmode=network.WLAN.{4}, password=password)
     except:
-        ap.config(essid=ssid, authmode=authmode, password=password)
+        ap.config(essid=ssid, authmode=network.WLAN.{4}, password=password)
 
-start_ap({0}, {1}, {2}, {3}, {4})
+start_ap({0}, {1}, {2}, {3})
 del start_ap
 """.format(
-            repr(ssid), security, repr(password), repr(hostname), ifconfig
+            repr(ssid), repr(password), repr(hostname), ifconfig, security
         )
 
         out, err = self.executeCommands(command, mode=self._submitMode, timeout=15000)
--- a/src/eric7/MicroPython/Devices/RP2Devices.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/Devices/RP2Devices.py	Fri Apr 25 16:23:02 2025 +0200
@@ -98,6 +98,25 @@
             },
         }
 
+        self.__securityMapping = {
+            "SEC_DPP": "DPP",
+            "SEC_OPEN": self.tr("Open"),
+            "SEC_OWE": "OWE",
+            "SEC_WAPI": "WAPI",
+            "SEC_WEP": "WEP",
+            "SEC_WPA": "WPA",
+            "SEC_WPA_WPA2": "WPA/WPA2",
+            "SEC_WPA2": "WPA2",
+            "SEC_WPA2_ENT": "WPA2 Enterprise",
+            "SEC_WPA2_WPA3": "WPA2/WPA3",
+            "SEC_WPA2_WPA3_ENT": "WPA2/WPA3 Enterprise",
+            "SEC_WPA3": "WPA3",
+            "SEC_WPA3_ENT": "WPA3 Enterprise",
+            "SEC_WPA3_ENT_192": "WPA3 Enterprise (192-bit)",
+            "SEC_WPA3_EXT_PSK": "WPA3 Extended",
+            "SEC_WPA3_EXT_PSK_MIXED_MODE": "WPA3 Extended, Mixed Mode",
+        }
+
     def setButtons(self):
         """
         Public method to enable the supported action buttons.
@@ -560,6 +579,12 @@
     import network
     import rp2
 
+    def security_str(mode):
+        for sm in [e for e in dir(network.WLAN) if e.startswith('SEC_')]:
+            if getattr(network.WLAN, sm, 0) == mode:
+                return sm
+        return ""
+
     wifi = network.WLAN(network.STA_IF)
     station = {
         'active': wifi.active(),
@@ -582,6 +607,7 @@
         'channel': wifi.config('channel'),
         'txpower': wifi.config('txpower'),
         'essid': wifi.config('essid'),
+        'ap_security': security_str(wifi.config('security')),
     }
     print(ujson.dumps(ap))
 
@@ -698,6 +724,12 @@
                 station["ap_security"] = self.tr("unknown ({0})").format(
                     station["ap_security"]
                 )
+        if "ap_security" in ap and self._deviceData["wifi_type"] == "picow":
+            try:
+                ap["ap_security"] = self.__securityMapping[ap["ap_security"]]
+            except KeyError:
+                ap["ap_security"] = self.tr("unknown ({0})").format(ap["ap_security"])
+
         return station, ap, overall
 
     def connectWifi(self, ssid, password, hostname):
@@ -1219,8 +1251,8 @@
 
         @param ssid SSID of the access point
         @type str
-        @param security security method (defaults to None)
-        @type int (optional)
+        @param security security mode (defaults to None) (unused)
+        @type str (optional)
         @param password password (defaults to None)
         @type str (optional)
         @param hostname host name of the device (defaults to None)
@@ -1232,15 +1264,13 @@
         @rtype tuple of (bool, str)
         """
         if security is None or password is None:
-            security = 0
+            security = "SEC_OPEN"
             password = ""  # secok
 
         if self._deviceData["wifi_type"] == "picow":
             country = Preferences.getMicroPython("WifiCountry").upper()
-            if security:
-                security = 4  # Pico W supports just WPA/WPA2
             command = """
-def start_ap(ssid, security, password, hostname, ifconfig, country):
+def start_ap(ssid, password, hostname, ifconfig, country):
     import network
     import rp2
     from time import sleep
@@ -1257,19 +1287,19 @@
     ap.active(True)
     if ifconfig:
         ap.ifconfig(ifconfig)
-    ap.config(ssid=ssid, security=security, password=password)
+    ap.config(ssid=ssid, security=network.WLAN.{5}, password=password)
     sleep(0.1)
     print(ap.status() == network.STAT_GOT_IP)
 
-start_ap({0}, {1}, {2}, {3}, {4}, {5})
+start_ap({0}, {1}, {2}, {3}, {4})
 del start_ap
 """.format(
                 repr(ssid),
-                security,
                 repr(password),
                 repr(hostname),
                 ifconfig,
                 repr(country if country else "XX"),
+                security,
             )
         elif self._deviceData["wifi_type"] == "picowireless":
             if ifconfig:
--- a/src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.py	Fri Apr 25 16:23:02 2025 +0200
@@ -21,29 +21,50 @@
     Class implementing a dialog to configure the Access Point interface.
     """
 
-    def __init__(self, withIP, parent=None):
+    def __init__(self, withIP, securityModes, parent=None):
         """
         Constructor
 
         @param withIP flag indicating to ask the user for an IP configuration
         @type bool
+        @param securityModes list of supported security modes
+        @type list of str
         @param parent reference to the parent widget (defaults to None)
         @type QWidget (optional)
         """
         super().__init__(parent)
         self.setupUi(self)
 
+        self.__securityMapping = {
+            "SEC_DPP": "DPP",
+            "SEC_OPEN": self.tr("Open"),
+            "SEC_OWE": "OWE",
+            "SEC_WAPI": "WAPI",
+            "SEC_WEP": "WEP",
+            "SEC_WPA": "WPA",
+            "SEC_WPA_WPA2": "WPA/WPA2",
+            "SEC_WPA2": "WPA2",
+            "SEC_WPA2_ENT": "WPA2 Enterprise",
+            "SEC_WPA2_WPA3": "WPA2/WPA3",
+            "SEC_WPA2_WPA3_ENT": "WPA2/WPA3 Enterprise",
+            "SEC_WPA3": "WPA3",
+            "SEC_WPA3_ENT": "WPA3 Enterprise",
+            "SEC_WPA3_ENT_192": "WPA3 Enterprise (192-bit)",
+            "SEC_WPA3_EXT_PSK": "WPA3 Extended",
+            "SEC_WPA3_EXT_PSK_MIXED_MODE": "WPA3 Extended, Mixed Mode",
+        }
+
         self.apShowPasswordButton.setIcon(EricPixmapCache.getIcon("showPassword"))
 
         # populate the WiFi security mode combo box
-        self.apSecurityComboBox.addItem(self.tr("open"), 0)
-        self.apSecurityComboBox.addItem("WEP", 1)
-        self.apSecurityComboBox.addItem("WPA", 2)
-        self.apSecurityComboBox.addItem("WPA2", 3)
-        self.apSecurityComboBox.addItem("WPA/WPA2", 4)
-        self.apSecurityComboBox.addItem("WPA2 (CCMP)", 5)
-        self.apSecurityComboBox.addItem("WPA3", 6)
-        self.apSecurityComboBox.addItem("WPA2/WPA3", 7)
+        for securityMode in sorted(securityModes):
+            try:
+                self.apSecurityComboBox.addItem(
+                    self.__securityMapping[securityMode], securityMode
+                )
+            except KeyError:
+                self.apSecurityComboBox.addItem(securityMode, securityMode)
+        self.apSecurityComboBox.model().sort(0)
 
         self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False)
 
@@ -54,7 +75,8 @@
             Preferences.getMicroPython("WifiApAuthMode")
         )
         if index == -1:
-            index = 5  # default it to WPA/WPA2 in case of an issue
+            index = self.apSecurityComboBox.findData("SEC_WPA_WPA2")
+            # default it to WPA/WPA2 in case of an issue
         self.apSecurityComboBox.setCurrentIndex(index)
         self.hostnameEdit.setText(Preferences.getMicroPython("WifiApHostname"))
 
@@ -90,7 +112,7 @@
         Private method to update the enabled state of the OK button.
         """
         enable = bool(self.apSsidEdit.text())
-        if self.apSecurityComboBox.currentData() != 0:
+        if self.apSecurityComboBox.currentData() != "SEC_OPEN":
             # security needs a password
             enable &= bool(self.apPasswordEdit.text())
         if self.__withIP:
@@ -138,6 +160,8 @@
                 Preferences.setMicroPython("WifiApGateway", self.gatewayEdit.text())
                 Preferences.setMicroPython("WifiApDNS", self.dnsEdit.text())
 
+            Preferences.syncPreferences()
+
         super().accept()
 
     def getApConfig(self):
--- a/src/eric7/MicroPython/WifiDialogs/WifiController.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/WifiDialogs/WifiController.py	Fri Apr 25 16:23:02 2025 +0200
@@ -302,13 +302,16 @@
         """
         from .WifiApConfigDialog import WifiApConfigDialog
 
-        dlg = WifiApConfigDialog(withIP=withIP, parent=self.__mpy)
+        securityModes = self.__mpy.getDevice().getSecurityModes()
+        dlg = WifiApConfigDialog(
+            withIP=withIP, securityModes=securityModes, parent=self.__mpy
+        )
         if dlg.exec() == QDialog.DialogCode.Accepted:
-            ssid, password, security, hostname, ifconfig = dlg.getApConfig()
+            ssid, password, securityMode, hostname, ifconfig = dlg.getApConfig()
 
             ok, err = self.__mpy.getDevice().startAccessPoint(
                 ssid,
-                security=security,
+                security=securityMode,
                 password=password,
                 hostname=hostname,
                 ifconfig=ifconfig if withIP else None,
--- a/src/eric7/MicroPython/WifiDialogs/WifiStatusDialog.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/MicroPython/WifiDialogs/WifiStatusDialog.py	Fri Apr 25 16:23:02 2025 +0200
@@ -183,6 +183,10 @@
                     QTreeWidgetItem(header, [self.tr("DNS"), apStatus["ifconfig"][3]])
                 with contextlib.suppress(KeyError):
                     QTreeWidgetItem(header, [self.tr("SSID"), apStatus["essid"]])
+                with contextlib.suppress(KeyError):
+                    QTreeWidgetItem(
+                        header, [self.tr("Security"), apStatus["ap_security"]]
+                    )
                 QTreeWidgetItem(header, [self.tr("MAC-Address"), apStatus["mac"]])
                 with contextlib.suppress(KeyError):
                     QTreeWidgetItem(
--- a/src/eric7/Preferences/__init__.py	Fri Apr 25 16:22:02 2025 +0200
+++ b/src/eric7/Preferences/__init__.py	Fri Apr 25 16:23:02 2025 +0200
@@ -1556,7 +1556,7 @@
         "WifiHostname": "",
         "WifiApName": "",
         "WifiApPassword": "",
-        "WifiApAuthMode": 4,  # WPA/WPA2
+        "WifiApAuthMode": "SEC_WPA_WPA2",
         "WifiApHostname": "",
         "WifiApAddress": "",
         "WifiApNetmask": "",
@@ -3940,7 +3940,6 @@
         "SerialTimeout",
         "WebreplTimeout",
         "ChartColorTheme",
-        "WifiApAuthMode",
         "NtpOffset",
         "NtpTimeout",
     ):

eric ide

mercurial