src/eric7/MicroPython/WifiDialogs/WifiStatusDialog.py

Mon, 05 May 2025 17:40:08 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 05 May 2025 17:40:08 +0200
branch
eric7
changeset 11263
28f0ead11a82
parent 11236
75c26fe1d1c7
permissions
-rw-r--r--

MicroPython
- Added support for IPv6 for WiFi and Ethernet enabled devices (MPy ≥ 1.24.0).

# -*- coding: utf-8 -*-

# Copyright (c) 2023 - 2025 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a dialog to show the WiFi status of the connected device.
"""

import contextlib

from PyQt6.QtCore import Qt, pyqtSlot
from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QTreeWidgetItem

from eric7.EricGui import EricPixmapCache
from eric7.SystemUtilities.NetworkUtilities import ipv6AddressScope

from .Ui_WifiStatusDialog import Ui_WifiStatusDialog


class WifiStatusDialog(QDialog, Ui_WifiStatusDialog):
    """
    Class implementing a dialog to show the WiFi status of the connected device.
    """

    def __init__(self, microPython, parent=None):
        """
        Constructor

        @param microPython reference to the MicroPython widget
        @type MicroPythonWidget
        @param parent reference to the parent widget (defaults to None)
        @type QWidget (optional)
        """
        super().__init__(parent)
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowType.Window)

        self.statusTree.setColumnCount(2)

        self.refreshButton.setIcon(EricPixmapCache.getIcon("reload"))
        self.refreshButton.clicked.connect(self.__showStatus)

        self.__mpy = microPython

        self.__showStatus()

    @pyqtSlot()
    def __showStatus(self):
        """
        Private slot to show the current WiFi status.
        """
        # clear old data
        self.statusTree.clear()

        # get the status
        try:
            clientStatus, apStatus, overallStatus = self.__mpy.getDevice().getWifiData()
        except Exception as exc:
            self.__mpy.showError("getWifiData()", str(exc))
            return

        # populate overall status
        QTreeWidgetItem(
            self.statusTree,
            [
                self.tr("Active"),
                self.tr("Yes") if overallStatus["active"] else self.tr("No"),
            ],
        )
        with contextlib.suppress(KeyError):
            QTreeWidgetItem(
                self.statusTree, [self.tr("Hostname"), overallStatus["hostname"]]
            )
        with contextlib.suppress(KeyError):
            QTreeWidgetItem(
                self.statusTree, [self.tr("Country"), overallStatus["country"]]
            )
        with contextlib.suppress(KeyError):
            QTreeWidgetItem(
                self.statusTree,
                [self.tr("Preferred IP Version"), str(overallStatus["prefer"])],
            )

        # populate status of client interface
        if clientStatus:
            header = self.__createHeader(self.tr("Client"))
            QTreeWidgetItem(
                header,
                [
                    self.tr("Active"),
                    self.tr("Yes") if clientStatus["active"] else self.tr("No"),
                ],
            )
            if clientStatus["active"]:
                QTreeWidgetItem(
                    header,
                    [
                        self.tr("Connected"),
                        self.tr("Yes") if clientStatus["connected"] else self.tr("No"),
                    ],
                )
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(header, [self.tr("Status"), clientStatus["status"]])
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(header, [self.tr("SSID"), clientStatus["essid"]])
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        header, [self.tr("Channel"), str(clientStatus["channel"])]
                    )
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        header, [self.tr("Country"), clientStatus["country"]]
                    )
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        header,
                        [
                            self.tr("Tx-Power"),
                            self.tr("{0} dBm").format(clientStatus["txpower"]),
                        ],
                    )
                QTreeWidgetItem(header, [self.tr("MAC-Address"), clientStatus["mac"]])

                # IPv4 specific data
                ip4Header = self.__createSubheader(header, self.tr("IPv4"))
                QTreeWidgetItem(
                    ip4Header, [self.tr("Address"), clientStatus["ifconfig"][0]]
                )
                QTreeWidgetItem(
                    ip4Header, [self.tr("Netmask"), clientStatus["ifconfig"][1]]
                )
                QTreeWidgetItem(
                    ip4Header, [self.tr("Gateway"), clientStatus["ifconfig"][2]]
                )
                QTreeWidgetItem(
                    ip4Header, [self.tr("DNS"), clientStatus["ifconfig"][3]]
                )

                # IPv6 specific data
                if clientStatus["ipv6_addr"]:
                    ip6Header = self.__createSubheader(header, self.tr("IPv6"))
                    ip6AddrHeader = self.__createSubheader(
                        ip6Header, self.tr("Addresses"), underlined=False
                    )
                    for addr in sorted(clientStatus["ipv6_addr"]):
                        QTreeWidgetItem(
                            ip6AddrHeader, [addr.lower(), ipv6AddressScope(addr)]
                        )

                # data about the connected access point
                if "ap_ssid" in clientStatus:
                    apHeader = self.__createSubheader(
                        header, self.tr("Connected Access Point")
                    )
                    QTreeWidgetItem(
                        apHeader, [self.tr("Name"), clientStatus["ap_ssid"]]
                    )
                    with contextlib.suppress(KeyError):
                        QTreeWidgetItem(
                            apHeader,
                            [self.tr("Channel"), str(clientStatus["ap_channel"])],
                        )
                    QTreeWidgetItem(
                        apHeader, [self.tr("MAC-Address"), clientStatus["ap_bssid"]]
                    )
                    QTreeWidgetItem(
                        apHeader, [self.tr("RSSI [dBm]"), str(clientStatus["ap_rssi"])]
                    )
                    QTreeWidgetItem(
                        apHeader, [self.tr("Security"), clientStatus["ap_security"]]
                    )
                    with contextlib.suppress(KeyError):
                        QTreeWidgetItem(
                            apHeader, [self.tr("Country"), clientStatus["ap_country"]]
                        )

        # populate status of access point interface
        if apStatus:
            header = self.__createHeader(self.tr("Access Point"))
            QTreeWidgetItem(
                header,
                [
                    self.tr("Active"),
                    self.tr("Yes") if apStatus["active"] else self.tr("No"),
                ],
            )
            if apStatus["active"]:
                QTreeWidgetItem(
                    header,
                    [
                        self.tr("Connected"),
                        self.tr("Yes") if apStatus["connected"] else self.tr("No"),
                    ],
                )
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(header, [self.tr("Status"), apStatus["status"]])
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(header, [self.tr("SSID"), apStatus["essid"]])
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        header, [self.tr("Security"), apStatus["ap_security"]]
                    )
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        header, [self.tr("Channel"), str(apStatus["channel"])]
                    )
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(header, [self.tr("Country"), apStatus["country"]])
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        header,
                        [
                            self.tr("Tx-Power"),
                            self.tr("{0} dBm").format(apStatus["txpower"]),
                        ],
                    )
                QTreeWidgetItem(header, [self.tr("MAC-Address"), apStatus["mac"]])

                # IPv4 specific data
                ip4Header = self.__createSubheader(header, self.tr("IPv4"))
                with contextlib.suppress(KeyError):
                    QTreeWidgetItem(
                        ip4Header, [self.tr("Address"), apStatus["ifconfig"][0]]
                    )
                    QTreeWidgetItem(
                        ip4Header, [self.tr("Netmask"), apStatus["ifconfig"][1]]
                    )
                    QTreeWidgetItem(
                        ip4Header, [self.tr("Gateway"), apStatus["ifconfig"][2]]
                    )
                    QTreeWidgetItem(
                        ip4Header, [self.tr("DNS"), apStatus["ifconfig"][3]]
                    )

                # IPv6 specific data
                if clientStatus["ipv6_addr"]:
                    ip6Header = self.__createSubheader(header, self.tr("IPv6"))
                    ip6AddrHeader = self.__createSubheader(
                        ip6Header, self.tr("Addresses"), underlined=False
                    )
                    for addr in sorted(apStatus["ipv6_addr"]):
                        QTreeWidgetItem(
                            ip6AddrHeader, [addr.lower(), ipv6AddressScope(addr)]
                        )

        for col in range(self.statusTree.columnCount()):
            self.statusTree.resizeColumnToContents(col)

        self.buttonBox.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.buttonBox.setFocus(Qt.FocusReason.OtherFocusReason)

    def __createHeader(self, headerText):
        """
        Private method to create a header item.

        @param headerText text for the header item
        @type str
        @return reference to the created header item
        @rtype QTreeWidgetItem
        """
        headerItem = QTreeWidgetItem(self.statusTree, [headerText])
        headerItem.setExpanded(True)
        headerItem.setFirstColumnSpanned(True)

        font = headerItem.font(0)
        font.setBold(True)
        headerItem.setFont(0, font)

        return headerItem

    def __createSubheader(self, parent, text, underlined=True):
        """
        Private method to create a subheader item.

        @param parent reference to the parent item
        @type QTreeWidgetItem
        @param text text for the header item
        @type str
        @param underlined flag indicating an underlined header (defaults to True)
        @type bool (optional)
        @return reference to the created header item
        @rtype QTreeWidgetItem
        """
        headerItem = QTreeWidgetItem(parent, [text])
        headerItem.setExpanded(True)
        headerItem.setFirstColumnSpanned(True)

        if underlined:
            font = headerItem.font(0)
            font.setUnderline(True)
            headerItem.setFont(0, font)

        return headerItem

eric ide

mercurial