Fri, 24 Feb 2023 14:11:20 +0100
MicroPython
- added functionality to start the access point interface with a given IPv4 configuration
--- a/eric7.epj Thu Feb 23 13:31:55 2023 +0100 +++ b/eric7.epj Fri Feb 24 14:11:20 2023 +0100 @@ -310,6 +310,7 @@ "src/eric7/Debugger/StartRunDialog.ui", "src/eric7/Debugger/VariableDetailDialog.ui", "src/eric7/Debugger/VariablesFilterDialog.ui", + "src/eric7/EricNetwork/EricIPv4InputWidget.ui", "src/eric7/EricNetwork/EricSslCertificateSelectionDialog.ui", "src/eric7/EricNetwork/EricSslCertificatesDialog.ui", "src/eric7/EricNetwork/EricSslCertificatesInfoDialog.ui", @@ -1155,6 +1156,7 @@ "src/eric7/EricNetwork/EricFtp.py", "src/eric7/EricNetwork/EricGoogleMail.py", "src/eric7/EricNetwork/EricGoogleMailHelpers.py", + "src/eric7/EricNetwork/EricIPv4InputWidget.py", "src/eric7/EricNetwork/EricJsonClient.py", "src/eric7/EricNetwork/EricJsonServer.py", "src/eric7/EricNetwork/EricJsonStreamReader.py",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/EricNetwork/EricIPv4InputWidget.py Fri Feb 24 14:11:20 2023 +0100 @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a widget to enter an IPv4 address. +""" + +import ipaddress + +from PyQt6.QtCore import pyqtSignal, pyqtSlot, QRegularExpression, QEvent, Qt +from PyQt6.QtGui import QRegularExpressionValidator +from PyQt6.QtWidgets import QWidget + +from eric7.EricGui import EricPixmapCache + +from .Ui_EricIPv4InputWidget import Ui_EricIPv4InputWidget + + +class EricIPv4InputWidget(QWidget, Ui_EricIPv4InputWidget): + """ + Class implementing a widget to enter an IPv4 address. + + @signal addressChanged() emitted to indicate a change of the entered IPv4 address + """ + addressChanged = pyqtSignal() + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.clearButton.setIcon(EricPixmapCache.getIcon("clearLeft")) + self.clearButton.clicked.connect(self.__clear) + + ipRange = r"(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])" + + self.ip1Edit.setValidator( + QRegularExpressionValidator(QRegularExpression(ipRange)) + ) + self.ip2Edit.setValidator( + QRegularExpressionValidator(QRegularExpression(ipRange)) + ) + self.ip3Edit.setValidator( + QRegularExpressionValidator(QRegularExpression(ipRange)) + ) + self.ip4Edit.setValidator( + QRegularExpressionValidator(QRegularExpression(ipRange)) + ) + + self.ip1Edit.installEventFilter(self) + self.ip2Edit.installEventFilter(self) + self.ip3Edit.installEventFilter(self) + + self.ip1Edit.textChanged.connect(self.addressChanged) + self.ip2Edit.textChanged.connect(self.addressChanged) + self.ip3Edit.textChanged.connect(self.addressChanged) + self.ip4Edit.textChanged.connect(self.addressChanged) + + def eventFilter(self, obj, evt): + """ + Public method to filter pressing '.' to give focus to the next input field. + + @param obj reference to the object + @type QObject + @param evt reference to the event object + @type QEvent + """ + if evt.type() == QEvent.Type.KeyPress: + if evt.text() == '.': + if obj is self.ip1Edit: + nextWidget = self.ip2Edit + elif obj is self.ip2Edit: + nextWidget = self.ip3Edit + elif obj is self.ip3Edit: + nextWidget = self.ip4Edit + else: + nextWidget = None + if nextWidget: + nextWidget.setFocus(Qt.FocusReason.TabFocusReason) + return True + + return super().eventFilter(obj, evt) + + def hasAcceptableInput(self): + """ + Public method to check, if the input is acceptable. + + @return flag indicating acceptable input + @rtype bool + """ + try: + ipaddress.IPv4Address(self.text()) + except ipaddress.AddressValueError: + # leading zeros are not allowed + return False + + return ( + self.ip1Edit.hasAcceptableInput() + and self.ip2Edit.hasAcceptableInput() + and self.ip3Edit.hasAcceptableInput() + and self.ip4Edit.hasAcceptableInput() + ) + + def text(self): + """ + Public method to get the IPv4 address as a string. + + @return IPv4 address + @rtype str + """ + return "{0}.{1}.{2}.{3}".format( + self.ip1Edit.text(), + self.ip2Edit.text(), + self.ip3Edit.text(), + self.ip4Edit.text(), + ) + + def setText(self, address): + """ + Public method to set the IPv4 address given a string. + + @param address IPv4 address + @type str + """ + if address: + try: + ipaddress.IPv4Address(address) + except ipaddress.AddressValueError as err: + raise ValueError(str(err)) + + addressParts = address.split(".") + self.ip1Edit.setText(addressParts[0]) + self.ip2Edit.setText(addressParts[1]) + self.ip3Edit.setText(addressParts[2]) + self.ip4Edit.setText(addressParts[3]) + else: + self.clear() + + def address(self): + """ + Public method to get the IPv4 address as an ipaddress.IPv4Address object. + + @return IPv4 address + @rtype ipaddress.IPv4Address + """ + try: + return ipaddress.IPv4Address(self.text()) + except ipaddress.AddressValueError as err: + raise ValueError(str(err)) + + def setAddress(self, address): + """ + Public method to set the IPv4 address given an ipaddress.IPv4Address object. + + @param address IPv4 address + @type ipaddress.IPv4Address + """ + if address: + self.setText(str(address)) + else: + self.clear() + + @pyqtSlot() + def clear(self): + """ + Public slot to clear the input fields. + """ + self.ip1Edit.clear() + self.ip2Edit.clear() + self.ip3Edit.clear() + self.ip4Edit.clear() + + @pyqtSlot() + def __clear(self): + """ + Private slot to handle the clear button press. + """ + self.clear() + self.ip1Edit.setFocus(Qt.FocusReason.OtherFocusReason)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/EricNetwork/EricIPv4InputWidget.ui Fri Feb 24 14:11:20 2023 +0100 @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>EricIPv4InputWidget</class> + <widget class="QWidget" name="EricIPv4InputWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>283</width> + <height>26</height> + </rect> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLineEdit" name="ip1Edit"> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="maxLength"> + <number>3</number> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string> . </string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="ip2Edit"> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="maxLength"> + <number>3</number> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string> . </string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="ip3Edit"> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="maxLength"> + <number>3</number> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string> . </string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="ip4Edit"> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="maxLength"> + <number>3</number> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="clearButton"> + <property name="toolTip"> + <string>Press to clear the entered IPv4 address</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui>
--- a/src/eric7/MicroPython/Devices/DeviceBase.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/Devices/DeviceBase.py Fri Feb 24 14:11:20 2023 +0100 @@ -1285,7 +1285,7 @@ """ return True, "" - def startAccessPoint(self, ssid, security=None, password=None): + def startAccessPoint(self, ssid, security=None, password=None, ifconfig=None): """ Public method to start the access point interface. @@ -1295,6 +1295,9 @@ @type int (optional) @param password password (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) @return tuple containing a flag indicating success and an error message @rtype tuple of (bool, str) """
--- a/src/eric7/MicroPython/Devices/EspDevices.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/Devices/EspDevices.py Fri Feb 24 14:11:20 2023 +0100 @@ -685,9 +685,10 @@ 'mac': ubinascii.hexlify(wifi.config('mac'), ':').decode(), } if wifi.active(): - station['txpower'] = wifi.config('txpower') - else: - station['txpower'] = 0 + try: + station['txpower'] = wifi.config('txpower') + except ValueError: + pass print(ujson.dumps(station)) wifi = network.WLAN(network.AP_IF) @@ -701,9 +702,10 @@ 'essid': wifi.config('essid'), } if wifi.active(): - ap['txpower'] = wifi.config('txpower') - else: - ap['txpower'] = 0 + try: + ap['txpower'] = wifi.config('txpower') + except ValueError: + pass print(ujson.dumps(ap)) wifi_status() @@ -1017,7 +1019,7 @@ else: return out.decode("utf-8").strip() == "True", "" - def startAccessPoint(self, ssid, security=None, password=None): + def startAccessPoint(self, ssid, security=None, password=None, ifconfig=None): """ Public method to start the access point interface. @@ -1027,6 +1029,9 @@ @type int (optional) @param password password (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) @return tuple containing a flag indicating success and an error message @rtype tuple of (bool, str) """ @@ -1037,21 +1042,23 @@ security = 4 # security >4 cause an error thrown by the ESP32 command = """ -def start_ap(): +def start_ap(ssid, authmode, password, ifconfig): import network ap = network.WLAN(network.AP_IF) ap.active(False) + if ifconfig: + ap.ifconfig(ifconfig) ap.active(True) try: - ap.config(ssid={0}, authmode={1}, password={2}) + ap.config(ssid=ssid, authmode=authmode, password=password) except: - ap.config(essid={0}, authmode={1}, password={2}) + ap.config(essid=ssid, authmode=authmode, password=password) -start_ap() +start_ap({0}, {1}, {2}, {3}) del start_ap """.format( - repr(ssid), security, repr(password) + repr(ssid), security, repr(password), ifconfig ) out, err = self._interface.execute(command, timeout=15000)
--- a/src/eric7/MicroPython/Devices/RP2040Devices.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/Devices/RP2040Devices.py Fri Feb 24 14:11:20 2023 +0100 @@ -813,7 +813,7 @@ else: return out.decode("utf-8").strip() == "True", "" - def startAccessPoint(self, ssid, security=None, password=None): + def startAccessPoint(self, ssid, security=None, password=None, ifconfig=None): """ Public method to start the access point interface. @@ -823,6 +823,9 @@ @type int (optional) @param password password (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) @return tuple containing a flag indicating success and an error message @rtype tuple of (bool, str) """ @@ -835,23 +838,29 @@ if security: security = 4 # Pico W supports just WPA/WPA2 command = """ -def start_ap(): +def start_ap(ssid, security, password, ifconfig, country): import network import rp2 from time import sleep - rp2.country({3}) + rp2.country(country) ap = network.WLAN(network.AP_IF) - ap.config(ssid={0}, security={1}, password={2}) ap.active(True) + if ifconfig: + ap.ifconfig(ifconfig) + ap.config(ssid=ssid, security=security, password=password) sleep(0.1) print(ap.isconnected()) -start_ap() +start_ap({0}, {1}, {2}, {3}, {4}) del start_ap """.format( - repr(ssid), security, repr(password), repr(country if country else "XX") + repr(ssid), + security, + repr(password), + ifconfig, + repr(country if country else "XX"), ) elif self._deviceData["wifi_type"] == "pimoroni": # TODO: not yet implemented
--- a/src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.py Fri Feb 24 14:11:20 2023 +0100 @@ -21,10 +21,12 @@ Class implementing a dialog to configure the Access Point interface. """ - def __init__(self, parent=None): + def __init__(self, withIP, parent=None): """ Constructor + @param withIP flag indicating to ask the user for an IP configuration + @type bool @param parent reference to the parent widget (defaults to None) @type QWidget (optional) """ @@ -45,11 +47,7 @@ self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(False) - self.apSsidEdit.textChanged.connect(self.__updateOk) - self.apPasswordEdit.textChanged.connect(self.__updateOk) - self.apSecurityComboBox.currentIndexChanged.connect(self.__updateOk) - - # populate the field with data saved to the preferences + # populate the WiFi fields with data saved to the preferences self.apSsidEdit.setText(Preferences.getMicroPython("WifiApName")) self.apPasswordEdit.setText(Preferences.getMicroPython("WifiApPassword")) index = self.apSecurityComboBox.findData( @@ -59,6 +57,29 @@ index = 5 # default it to WPA/WPA2 in case of an issue self.apSecurityComboBox.setCurrentIndex(index) + self.__withIP = withIP + + self.ipv4GroupBox.setVisible(withIP) + if withIP: + # populate the IPv4 configuration with data saved to the preferences + self.addressEdit.setText(Preferences.getMicroPython("WifiApAddress")) + self.netmaskEdit.setText(Preferences.getMicroPython("WifiApNetmask")) + self.gatewayEdit.setText(Preferences.getMicroPython("WifiApGateway")) + self.dnsEdit.setText(Preferences.getMicroPython("WifiApDNS")) + + # connect the IPv4 fields + self.addressEdit.addressChanged.connect(self.__updateOk) + self.netmaskEdit.addressChanged.connect(self.__updateOk) + self.gatewayEdit.addressChanged.connect(self.__updateOk) + self.dnsEdit.addressChanged.connect(self.__updateOk) + + # connect the WiFi fields + self.apSsidEdit.textChanged.connect(self.__updateOk) + self.apPasswordEdit.textChanged.connect(self.__updateOk) + self.apSecurityComboBox.currentIndexChanged.connect(self.__updateOk) + + self.__updateOk() + msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @@ -71,6 +92,13 @@ if self.apSecurityComboBox.currentData() != 0: # security needs a password enable &= bool(self.apPasswordEdit.text()) + if self.__withIP: + enable &= ( + self.addressEdit.hasAcceptableInput() + and self.netmaskEdit.hasAcceptableInput() + and self.gatewayEdit.hasAcceptableInput() + and self.dnsEdit.hasAcceptableInput() + ) self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled(enable) @@ -99,9 +127,20 @@ and a flag indicating to save the parameters to the settings @rtype tuple of (str, str, int, bool) """ + if self.__withIP: + ifconfig = ( + self.addressEdit.text(), + self.netmaskEdit.text(), + self.gatewayEdit.text(), + self.dnsEdit.text(), + ) + else: + ifconfig = ("", "", "", "") + return ( self.apSsidEdit.text(), self.apPasswordEdit.text(), self.apSecurityComboBox.currentData(), self.rememberCheckBox.isChecked(), + ifconfig, )
--- a/src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.ui Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/WifiDialogs/WifiApConfigDialog.ui Fri Feb 24 14:11:20 2023 +0100 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>400</width> - <height>172</height> + <height>315</height> </rect> </property> <property name="windowTitle"> @@ -16,7 +16,7 @@ <property name="sizeGripEnabled"> <bool>true</bool> </property> - <layout class="QGridLayout" name="gridLayout"> + <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QLabel" name="label_10"> <property name="text"> @@ -96,6 +96,88 @@ </layout> </item> <item row="3" column="0" colspan="3"> + <widget class="QGroupBox" name="ipv4GroupBox"> + <property name="title"> + <string>IPv4 Configuration</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Address:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="EricIPv4InputWidget" name="addressEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Netmask:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="EricIPv4InputWidget" name="netmaskEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Gateway:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="EricIPv4InputWidget" name="gatewayEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>DNS:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="EricIPv4InputWidget" name="dnsEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>273</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="4" column="0" colspan="3"> <widget class="QCheckBox" name="rememberCheckBox"> <property name="toolTip"> <string>Select to remember the entered connection parameters</string> @@ -105,7 +187,7 @@ </property> </widget> </item> - <item row="4" column="0" colspan="3"> + <item row="5" column="0" colspan="3"> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -117,11 +199,23 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>EricIPv4InputWidget</class> + <extends>QWidget</extends> + <header>eric7/EricNetwork/EricIPv4InputWidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> <tabstops> <tabstop>apSsidEdit</tabstop> <tabstop>apPasswordEdit</tabstop> <tabstop>apShowPasswordButton</tabstop> <tabstop>apSecurityComboBox</tabstop> + <tabstop>addressEdit</tabstop> + <tabstop>netmaskEdit</tabstop> + <tabstop>gatewayEdit</tabstop> + <tabstop>dnsEdit</tabstop> <tabstop>rememberCheckBox</tabstop> </tabstops> <resources/>
--- a/src/eric7/MicroPython/WifiDialogs/WifiController.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/WifiDialogs/WifiController.py Fri Feb 24 14:11:20 2023 +0100 @@ -57,6 +57,9 @@ wifiMenu.addSeparator() wifiMenu.addAction(self.tr("Start WiFi Access Point"), self.__startAccessPoint) wifiMenu.addAction( + self.tr("Start WiFi Access Point with IP"), self.__startAccessPointIP + ) + wifiMenu.addAction( self.tr("Show Connected Clients"), self.__showConnectedClients ) wifiMenu.addAction(self.tr("Stop WiFi Access Point"), self.__stopAccessPoint) @@ -256,23 +259,34 @@ ) @pyqtSlot() - def __startAccessPoint(self): + def __startAccessPoint(self, withIP=False): """ Private slot to start the Access Point interface of the connected device. + + @param withIP flag indicating to start the access point with an IP configuration + @type bool """ from .WifiApConfigDialog import WifiApConfigDialog - dlg = WifiApConfigDialog() + dlg = WifiApConfigDialog(withIP=withIP) if dlg.exec() == QDialog.DialogCode.Accepted: - ssid, password, security, remember = dlg.getApConfig() + ssid, password, security, remember, ifconfig = dlg.getApConfig() if remember: Preferences.setMicroPython("WifiApName", ssid) Preferences.setMicroPython("WifiApPassword", password) Preferences.setMicroPython("WifiApAuthMode", security) + if withIP: + Preferences.setMicroPython("WifiApAddress", ifconfig[0]) + Preferences.setMicroPython("WifiApNetmask", ifconfig[1]) + Preferences.setMicroPython("WifiApGateway", ifconfig[2]) + Preferences.setMicroPython("WifiApDNS", ifconfig[3]) ok, err = self.__mpy.getDevice().startAccessPoint( - ssid, security=security, password=password + ssid, + security=security, + password=password, + ifconfig=ifconfig if withIP else None, ) if ok: EricMessageBox.information( @@ -293,6 +307,14 @@ ) @pyqtSlot() + def __startAccessPointIP(self): + """ + Private slot to start the Access Point interface of the connected device + with given IP parameters. + """ + self.__startAccessPoint(withIP=True) + + @pyqtSlot() def __stopAccessPoint(self): """ Private slot to stop the Access Point interface of the connected device.
--- a/src/eric7/MicroPython/WifiDialogs/WifiStatusDialog.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/MicroPython/WifiDialogs/WifiStatusDialog.py Fri Feb 24 14:11:20 2023 +0100 @@ -75,13 +75,14 @@ QTreeWidgetItem( header, [self.tr("Country"), clientStatus["country"]] ) - QTreeWidgetItem( - header, - [ - self.tr("Tx-Power"), - self.tr("{0} dBm").format(clientStatus["txpower"]), - ], - ) + with contextlib.suppress(KeyError): + QTreeWidgetItem( + header, + [ + self.tr("Tx-Power"), + self.tr("{0} dBm").format(clientStatus["txpower"]), + ], + ) # access point interface if apStatus: @@ -113,13 +114,14 @@ QTreeWidgetItem(header, [self.tr("Channel"), str(apStatus["channel"])]) with contextlib.suppress(KeyError): QTreeWidgetItem(header, [self.tr("Country"), apStatus["country"]]) - QTreeWidgetItem( - header, - [ - self.tr("Tx-Power"), - self.tr("{0} dBm").format(apStatus["txpower"]), - ], - ) + with contextlib.suppress(KeyError): + QTreeWidgetItem( + header, + [ + self.tr("Tx-Power"), + self.tr("{0} dBm").format(apStatus["txpower"]), + ], + ) for col in range(self.statusTree.columnCount()): self.statusTree.resizeColumnToContents(col)
--- a/src/eric7/Preferences/ConfigurationPages/MicroPythonPage.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/Preferences/ConfigurationPages/MicroPythonPage.py Fri Feb 24 14:11:20 2023 +0100 @@ -142,6 +142,10 @@ if index == -1: index = 5 # default it to WPA/WPA2 in case of an issue self.apSecurityComboBox.setCurrentIndex(index) + self.apAddressEdit.setText(Preferences.getMicroPython("WifiApAddress")) + self.apNetmaskEdit.setText(Preferences.getMicroPython("WifiApNetmask")) + self.apGatewayEdit.setText(Preferences.getMicroPython("WifiApGateway")) + self.apDnsEdit.setText(Preferences.getMicroPython("WifiApDNS")) # MPY Cross Compiler self.mpyCrossPicker.setText(Preferences.getMicroPython("MpyCrossCompiler")) @@ -232,6 +236,10 @@ Preferences.setMicroPython( "WifiApAuthMode", self.apSecurityComboBox.currentData() ) + Preferences.setMicroPython("WifiApAddress", self.apAddressEdit.text()) + Preferences.setMicroPython("WifiApNetmask", self.apNetmaskEdit.text()) + Preferences.setMicroPython("WifiApGateway", self.apGatewayEdit.text()) + Preferences.setMicroPython("WifiApDNS", self.apDnsEdit.text()) # MPY Cross Compiler Preferences.setMicroPython("MpyCrossCompiler", self.mpyCrossPicker.text())
--- a/src/eric7/Preferences/ConfigurationPages/MicroPythonPage.ui Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/Preferences/ConfigurationPages/MicroPythonPage.ui Fri Feb 24 14:11:20 2023 +0100 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>541</width> - <height>1617</height> + <height>1847</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout_3"> @@ -317,7 +317,7 @@ <property name="title"> <string>Access Point</string> </property> - <layout class="QGridLayout" name="gridLayout_9"> + <layout class="QGridLayout" name="gridLayout_10"> <item row="0" column="0"> <widget class="QLabel" name="label_10"> <property name="text"> @@ -396,6 +396,91 @@ </item> </layout> </item> + <item row="3" column="0" colspan="3"> + <widget class="QGroupBox" name="ipv4GroupBox"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + <property name="title"> + <string>IPv4 Configuration</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_7"> + <item> + <layout class="QGridLayout" name="gridLayout_9"> + <item row="0" column="0"> + <widget class="QLabel" name="label_24"> + <property name="text"> + <string>Address:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="EricIPv4InputWidget" name="apAddressEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_25"> + <property name="text"> + <string>Netmask:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="EricIPv4InputWidget" name="apNetmaskEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_26"> + <property name="text"> + <string>Gateway:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="EricIPv4InputWidget" name="apGatewayEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_27"> + <property name="text"> + <string>DNS:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="EricIPv4InputWidget" name="apDnsEdit" native="true"> + <property name="focusPolicy"> + <enum>Qt::NoFocus</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>273</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> </layout> </widget> </item> @@ -740,6 +825,12 @@ <header>eric7/EricWidgets/EricPathPicker.h</header> <container>1</container> </customwidget> + <customwidget> + <class>EricIPv4InputWidget</class> + <extends>QWidget</extends> + <header>eric7/EricNetwork/EricIPv4InputWidget.h</header> + <container>1</container> + </customwidget> </customwidgets> <tabstops> <tabstop>workspacePicker</tabstop> @@ -757,6 +848,7 @@ <tabstop>apPasswordEdit</tabstop> <tabstop>apShowPasswordButton</tabstop> <tabstop>apSecurityComboBox</tabstop> + <tabstop>ipv4GroupBox</tabstop> <tabstop>mpyCrossPicker</tabstop> <tabstop>dfuUtilPathPicker</tabstop> <tabstop>micropythonFirmwareUrlLineEdit</tabstop>
--- a/src/eric7/Preferences/__init__.py Thu Feb 23 13:31:55 2023 +0100 +++ b/src/eric7/Preferences/__init__.py Fri Feb 24 14:11:20 2023 +0100 @@ -1581,6 +1581,10 @@ "WifiApName": "", "WifiApPassword": "", "WifiApAuthMode": 4, # WPA/WPA2 + "WifiApAddress": "", + "WifiApNetmask": "", + "WifiApGateway": "", + "WifiApDNS": "", "WifiCountry": "", # MicroPython URLs "MicroPythonDocuUrl": "https://docs.micropython.org/en/latest/",