diff -r 33e7b9d3f91c -r ffe7432f716b src/eric7/MicroPython/Devices/EspDevices.py --- a/src/eric7/MicroPython/Devices/EspDevices.py Wed Aug 02 17:22:20 2023 +0200 +++ b/src/eric7/MicroPython/Devices/EspDevices.py Thu Aug 03 17:33:07 2023 +0200 @@ -615,6 +615,18 @@ ## Methods below implement WiFi related methods ################################################################## + def addDeviceWifiEntries(self, menu): + """ + Public method to add device specific entries to the given menu. + + @param menu reference to the context menu + @type QMenu + """ + if not self.hasCircuitPython(): + menu.addSeparator() + menu.addAction(self.tr("Set Country"), self.__setCountry) + menu.addAction(self.tr("Reset Country"), self.__resetCountry) + def hasWifi(self): """ Public method to check the availability of WiFi. @@ -629,6 +641,15 @@ return True, "esp32" + def hasWifiCountry(self): + """ + Public method to check, if the device has support to set the WiFi country. + + @return flag indicating the support of WiFi country + @rtype bool + """ + return True + def getWifiData(self): """ Public method to get data related to the current WiFi status. @@ -682,6 +703,14 @@ overall = { 'active': station['active'] or ap['active'] } + try: + overall['hostname'] = network.hostname() + except AttributeError: + pass + try: + overall['country'] = network.country() + except AttributeError: + pass print(ujson.dumps(overall)) wifi_status() @@ -706,7 +735,7 @@ ap["status"] = str(ap["status"]) return station, ap, overall - def connectWifi(self, ssid, password): + def connectWifi(self, ssid, password, hostname): """ Public method to connect a device to a WiFi network. @@ -714,18 +743,26 @@ @type str @param password password needed to connect @type str + @param hostname host name of the device + @type str @return tuple containing the connection status and an error string @rtype tuple of (bool, str) """ if self.hasCircuitPython(): - return self.__cpyDevice.connectWifi(ssid, password) + return self.__cpyDevice.connectWifi(ssid, password, hostname) command = """ -def connect_wifi(ssid, password): +def connect_wifi(ssid, password, hostname): import network import ujson from time import sleep + if hostname: + try: + network.hostname(hostname) + except AttributeError: + pass + wifi = network.WLAN(network.STA_IF) wifi.active(False) wifi.active(True) @@ -737,11 +774,12 @@ 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), repr(password if password else ""), + repr(hostname), ) with EricOverrideCursor(): @@ -847,7 +885,7 @@ return out.strip() == b"True" - def writeCredentials(self, ssid, password): + def writeCredentials(self, ssid, password, hostname, country): """ Public method to write the given credentials to the connected device and modify the start script to connect automatically. @@ -856,25 +894,34 @@ @type str @param password password needed to authenticate @type str + @param hostname host name of the device + @type str + @param country WiFi country code + @type str @return tuple containing a flag indicating success and an error message @rtype tuple of (bool, str) """ if self.hasCircuitPython(): - return self.__cpyDevice.writeCredentials(ssid, password) + return self.__cpyDevice.writeCredentials(ssid, password, hostname) nvsCommand = """ -def save_wifi_creds(ssid, password): +def save_wifi_creds(ssid, password, hostname, country): import esp32 nvs = esp32.NVS('wifi_creds') nvs.set_blob('ssid', ssid) nvs.set_blob('password', password) + nvs.set_blob('hostname', hostname) + nvs.set_blob('country', country) nvs.commit() -save_wifi_creds({0}, {1}) +save_wifi_creds({0}, {1}, {2}, {3}) del save_wifi_creds """.format( - repr(ssid), repr(password) if password else "''" + repr(ssid), + repr(password) if password else "''", + repr(hostname) if hostname else "''", + repr(country.upper()) if country else "''", ) bootCommand = """ def modify_boot(): @@ -1075,7 +1122,14 @@ else: return out.decode("utf-8").strip() == "True", "" - def startAccessPoint(self, ssid, security=None, password=None, ifconfig=None): + def startAccessPoint( + self, + ssid, + security=None, + password=None, + hostname=None, + ifconfig=None, + ): """ Public method to start the access point interface. @@ -1085,6 +1139,8 @@ @type int (optional) @param password password (defaults to None) @type str (optional) + @param hostname host name of the device (defaults to None) + @type str (optional) @param ifconfig IPv4 configuration for the access point if not default (IPv4 address, netmask, gateway address, DNS server address) @type tuple of (str, str, str, str) @@ -1093,7 +1149,11 @@ """ if self.hasCircuitPython(): return self.__cpyDevice.startAccessPoint( - ssid, security=security, password=password, ifconfig=ifconfig + ssid, + security=security, + password=password, + hostname=hostname, + ifconfig=ifconfig, ) if security is None or password is None: @@ -1103,9 +1163,15 @@ security = 4 # security >4 cause an error thrown by the ESP32 command = """ -def start_ap(ssid, authmode, password, ifconfig): +def start_ap(ssid, authmode, password, hostname, ifconfig): import network + if hostname: + try: + network.hostname(hostname) + except AttributeError: + pass + ap = network.WLAN(network.AP_IF) ap.active(False) if ifconfig: @@ -1116,10 +1182,10 @@ except: ap.config(essid=ssid, authmode=authmode, password=password) -start_ap({0}, {1}, {2}, {3}) +start_ap({0}, {1}, {2}, {3}, {4}) del start_ap """.format( - repr(ssid), security, repr(password), ifconfig + repr(ssid), security, repr(password), repr(hostname), ifconfig ) out, err = self.executeCommands(command, mode=self._submitMode, timeout=15000) @@ -1259,6 +1325,55 @@ return out.decode("utf-8").strip() == "True", "" + @pyqtSlot() + def __setCountry(self): + """ + Private slot to configure the country of the connected ESP32 device. + + The country is the two-letter ISO 3166-1 Alpha-2 country code. + """ + from ..WifiDialogs.WifiCountryDialog import WifiCountryDialog + + dlg = WifiCountryDialog() + if dlg.exec() == QDialog.DialogCode.Accepted: + country, remember = dlg.getCountry() + if remember: + Preferences.setMicroPython("WifiCountry", country) + + command = """ +try: + import network + network.country({0}) +except AttributeError: + pass +""".format( + repr(country) + ) + + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + self.microPython.showError("country()", err) + + @pyqtSlot() + def __resetCountry(self): + """ + Private slot to reset the country of the connected ESP32 device. + + The country is the two-letter ISO 3166-1 Alpha-2 country code. This method + resets it to the default code 'XX' representing the "worldwide" region. + """ + command = """ +try: + import network + network.country('XX') +except AttributeError: + pass +""" + + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + self.microPython.showError("country()", err) + ################################################################## ## Methods below implement Bluetooth related methods ##################################################################