src/eric7/MicroPython/Devices/RP2040Devices.py

branch
mpy_network
changeset 9787
163511257f24
parent 9782
67414f28db68
child 9788
12294115900a
--- a/src/eric7/MicroPython/Devices/RP2040Devices.py	Tue Feb 21 10:53:46 2023 +0100
+++ b/src/eric7/MicroPython/Devices/RP2040Devices.py	Wed Feb 22 07:45:54 2023 +0100
@@ -11,6 +11,7 @@
 import ast
 import binascii
 import json
+import os
 
 from PyQt6.QtCore import QUrl, pyqtSlot
 from PyQt6.QtNetwork import QNetworkRequest
@@ -506,13 +507,13 @@
         if self._deviceData["wifi_type"] == "picow":
             country = Preferences.getMicroPython("WifiCountry").upper()
             command = """
-def connect_wifi(ssid, password):
+def connect_wifi(ssid, password, country):
     import network
     import rp2
     import ujson
     from time import sleep
 
-    rp2.country({2})
+    rp2.country(country)
 
     wifi = network.WLAN(network.STA_IF)
     wifi.active(False)
@@ -527,7 +528,7 @@
     status = wifi.status()
     print(ujson.dumps({{'connected': wifi.isconnected(), 'status': status}}))
 
-connect_wifi({0}, {1})
+connect_wifi({0}, {1}, {2})
 del connect_wifi
 """.format(
             repr(ssid),
@@ -592,6 +593,86 @@
 
         return out.decode("utf-8").strip() == "True", ""
 
+    def writeCredentials(self, ssid, password):
+        """
+        Public method to write the given credentials to the connected device and modify
+        the start script to connect automatically.
+
+        @param ssid SSID of the network to connect to
+        @type str
+        @param password password needed to authenticate
+        @type str
+        @return tuple containing a flag indicating success and an error message
+        @rtype tuple of (bool, str)
+        """
+        command = """
+def modify_boot():
+    add = True
+    try:
+        with open('/boot.py', 'r') as f:
+            for ln in f.readlines():
+                if 'wifi_connect' in ln:
+                    add = False
+                    break
+    except:
+        pass
+    if add:
+        with open('/boot.py', 'a') as f:
+            f.write('\\nimport wifi_connect\\n')
+    print(True)
+
+modify_boot()
+del modify_boot
+"""
+
+        if self._deviceData["wifi_type"] == "picow":
+            country = Preferences.getMicroPython("WifiCountry").upper()
+            secrets = "WIFI_SSID = {0}\nWIFI_KEY = {1}\nWIFI_COUNTRY={2}".format(
+                repr(ssid),
+                repr(password) if password else '""',
+                repr(country) if country else '""'
+            )
+            wifiConnectFile = "picowWiFiConnect.py"
+        else:
+            secrets = "WIFI_SSID = {0}\nWIFI_KEY = {1}\n".format(
+                repr(ssid),
+                repr(password) if password else '""',
+            )
+            wifiConnectFile = "mpyWiFiConnect.py"
+        try:
+            # write secrets file
+            self.putData("/secrets.py", secrets.encode("utf-8"))
+            # copy auto-connect file
+            self.put(
+                os.path.join(
+                    os.path.dirname(__file__), "MCUScripts", wifiConnectFile
+                ),
+                "/wifi_connect.py",
+            )
+        except OSError as err:
+            return False, str(err)
+
+        # modify boot.py
+        out, err = self._interface.execute(command)
+        if err:
+            return False, err
+
+        return out.decode("utf-8").strip() == "True", ""
+
+    def removeCredentials(self):
+        """
+        Public method to remove the saved credentials from the connected device.
+
+        @return tuple containing a flag indicating success and an error message
+        @rtype tuple of (bool, str)
+        """
+        try:
+            self.rm("/secrets.py")
+        except OSError as err:
+            return False, str(err)
+
+        return True, ""
+
     def checkInternet(self):
         """
         Public method to check, if the internet can be reached.
@@ -641,9 +722,13 @@
         @rtype tuple of (list of tuple of (str, str, int, int, str), str)
         """
         if self._deviceData["wifi_type"] == "picow":
+            country = Preferences.getMicroPython("WifiCountry").upper()
             command = """
 def scan_networks():
     import network
+    import rp2
+
+    rp2.country({0})
 
     wifi = network.WLAN(network.STA_IF)
     active = wifi.active()
@@ -656,7 +741,8 @@
 
 scan_networks()
 del scan_networks
-"""
+""".format(repr(country if country else "XX"))
+
         elif self._deviceData["wifi_type"] == "pimoroni":
             # TODO: not yet implemented
             pass
@@ -725,13 +811,55 @@
         else:
             return out.decode("utf-8").strip() == "True", ""
 
-    def startAccessPoint(self):
+    def startAccessPoint(self, ssid, security=None, password=None):
         """
         Public method to start the access point interface.
 
+        @param ssid SSID of the access point
+        @type str
+        @param security security method (defaults to None)
+        @type int (optional)
+        @param password password (defaults to None)
+        @type str (optional)
         @return tuple containing a flag indicating success and an error message
         @rtype tuple of (bool, str)
         """
+        if security is None or password is None:
+            security = 0
+            password = ""
+
+        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():
+    import network
+    import rp2
+    from time import sleep
+
+    rp2.country({3})
+
+    ap = network.WLAN(network.AP_IF)
+    ap.config(ssid={0}, security={1}, password={2})
+    ap.active(True)
+    sleep(0.1)
+    print(ap.isconnected())
+
+start_ap()
+del start_ap
+""".format(repr(ssid), security, repr(password), repr(country if country else "XX"))
+        elif self._deviceData["wifi_type"] == "pimoroni":
+            # TODO: not yet implemented
+            pass
+        else:
+            return super().startAccessPoint(ssid, security=security, password=password)
+
+        out, err = self._interface.execute(command, timeout=15000)
+        if err:
+            return False, err
+        else:
+            return out.decode("utf-8").strip() == "True", ""
 
     def stopAccessPoint(self):
         """
@@ -748,6 +876,39 @@
         else:
             return super().stopAccessPoint()
 
+    def getConnectedClients(self):
+        """
+        Public method to get a list of connected clients.
+
+        @return a tuple containing a list of tuples containing the client MAC-Address
+            and the RSSI (if supported and available) and an error message
+        @rtype tuple of ([(bytes, int)], str)
+        """
+        if self._deviceData["wifi_type"] == "picow":
+            command = """
+def get_stations():
+    import network
+
+    ap = network.WLAN(network.AP_IF)
+    stations = ap.status('stations')
+    print(stations)
+
+get_stations()
+del get_stations
+"""
+        elif self._deviceData["wifi_type"] == "pimoroni":
+            # TODO: not yet implemented
+            pass
+        else:
+            return super().checkInternet()
+
+        out, err = self._interface.execute(command, timeout=10000)
+        if err:
+            return [], err
+
+        clientsList = ast.literal_eval(out.decode("utf-8"))
+        return clientsList, ""
+
     ############################################################################
     ## RP2 only methods below
     ############################################################################
@@ -774,7 +935,7 @@
 
             out, err = self._interface.execute(command)
             if err:
-                self._showError("rp2.country()", err)
+                self.microPython.showError("rp2.country()", err)
 
 
 def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber):

eric ide

mercurial