Sistem Asistanı (v1.1) / sayfalar/wifi_analiz.py
wifi_analiz.py 253 satır • 10.02 KB
# sayfalar/wifi_analiz.py

from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, 
                             QTableWidget, QTableWidgetItem, QHeaderView, 
                             QPushButton, QProgressBar, QCheckBox, QFrame)
from PyQt6.QtCore import Qt, QThread, pyqtSignal, QTimer
from PyQt6.QtGui import QColor # <--- EKLENDİ
from gorsel_araclar import SayfaBasligi, SvgIkonOlusturucu
import subprocess
import re

class WifiScanner(QThread):
    # (SSID, Sinyal, Kanal, Güvenlik, Frekans, BSSID, Aktif_Mi)
    sonuc_sinyali = pyqtSignal(list) 
    hata_sinyali = pyqtSignal(str)

    def run(self):
        try:
            # -f IN-USE ekleyerek aktif ağı tespit ediyoruz (* işareti gelir)
            cmd = ["nmcli", "-t", "-f", "IN-USE,SSID,SIGNAL,CHAN,SECURITY,FREQ,BSSID", "dev", "wifi"]
            
            # Arka planda taramayı tetikle (Sessizce)
            subprocess.run(["nmcli", "dev", "wifi", "rescan"], stderr=subprocess.DEVNULL)
            
            try:
                out = subprocess.check_output(cmd, text=True, stderr=subprocess.DEVNULL)
            except subprocess.CalledProcessError:
                out = ""
            
            networks = []
            
            for line in out.splitlines():
                if not line.strip(): continue
                
                # Kaçış karakterlerini düzelt
                parts = line.replace("\\:", "|COLON|").split(":")
                
                if len(parts) >= 7:
                    in_use = parts[0].strip() == "*"
                    ssid = parts[1].replace("|COLON|", ":").strip()
                    if not ssid: ssid = "<Gizli Ağ>"
                    
                    try: signal = int(parts[2])
                    except: signal = 0
                    
                    chan = parts[3]
                    sec = parts[4]
                    freq = parts[5]
                    bssid = parts[6].replace("|COLON|", ":")
                    
                    # Frekans Ayrımı
                    band = "2.4 GHz"
                    try:
                        f_val = int(freq.split()[0])
                        if f_val > 5000: band = "5 GHz"
                    except: pass

                    networks.append((ssid, signal, chan, sec, band, bssid, in_use))
            
            # Sıralama: Önce Aktif Ağ, Sonra Sinyal Gücü
            networks.sort(key=lambda x: (not x[6], -x[1]))
            
            self.sonuc_sinyali.emit(networks)

        except Exception as e:
            self.hata_sinyali.emit(str(e))

class WifiAnalizSayfasi(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QVBoxLayout(self)
        icon = SvgIkonOlusturucu.network_ikonu("#e67e22", 32)
        layout.addWidget(SayfaBasligi("Gelişmiş Wi-Fi Analizörü", icon))

        # --- ÜST PANEL ---
        self.suggestion_box = QFrame()
        self.suggestion_box.setStyleSheet("""
            QFrame {
                background-color: rgba(51, 170, 221, 0.08); 
                border: 1px solid rgba(51, 170, 221, 0.3); 
                border-radius: 6px;
            }
        """)
        l_sugg = QVBoxLayout(self.suggestion_box)
        l_sugg.setContentsMargins(15, 15, 15, 15)
        
        self.lbl_oneri = QLabel("Analiz Bekleniyor...")
        self.lbl_oneri.setStyleSheet("font-size: 10pt; color: #33AADD; border: none; background: transparent;")
        self.lbl_oneri.setWordWrap(True)
        self.lbl_oneri.setTextFormat(Qt.TextFormat.RichText)
        l_sugg.addWidget(self.lbl_oneri)
        layout.addWidget(self.suggestion_box)

        # --- KONTROLLER ---
        h_top = QHBoxLayout()
        self.chk_auto = QCheckBox("Otomatik Yenile (5sn)")
        self.chk_auto.stateChanged.connect(self.oto_yenileme_degisti)
        
        self.btn_tara = QPushButton("📡 Şimdi Tara")
        self.btn_tara.setStyleSheet("background-color: #e67e22; color: white; font-weight: bold; padding: 6px 15px;")
        self.btn_tara.clicked.connect(self.tara)
        
        h_top.addWidget(self.chk_auto)
        h_top.addStretch()
        h_top.addWidget(self.btn_tara)
        layout.addLayout(h_top)

        # --- TABLO ---
        self.table = QTableWidget()
        self.table.setColumnCount(6)
        self.table.setHorizontalHeaderLabels(["Ağ Adı (SSID)", "Sinyal", "Kanal", "Bant", "Güvenlik", "MAC Adresi"])
        self.table.verticalHeader().setVisible(False)
        self.table.setAlternatingRowColors(True)
        
        # Sütun Genişlikleri
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch) 
        header.setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed); self.table.setColumnWidth(1, 120)
        header.setSectionResizeMode(2, QHeaderView.ResizeMode.Fixed); self.table.setColumnWidth(2, 60)
        header.setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed); self.table.setColumnWidth(3, 80)
        
        layout.addWidget(self.table)

        # --- BİLGİ ---
        lbl_legend = QLabel("■ Yeşil: Mükemmel (>70%)  ■ Sarı: İyi (>40%)  ■ Kırmızı: Zayıf")
        lbl_legend.setStyleSheet("color: palette(mid); font-size: 9pt; margin-top: 5px;")
        lbl_legend.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(lbl_legend)

        self.timer = QTimer()
        self.timer.timeout.connect(self.tara)
        self.tara()

    def oto_yenileme_degisti(self, state):
        if state == 2:
            self.tara()
            self.timer.start(5000)
            self.btn_tara.setEnabled(False)
        else:
            self.timer.stop()
            self.btn_tara.setEnabled(True)

    def tara(self):
        if not self.chk_auto.isChecked():
            self.btn_tara.setEnabled(False)
            self.btn_tara.setText("Taranıyor...")
        
        self.worker = WifiScanner()
        self.worker.sonuc_sinyali.connect(self.sonuc_goster)
        self.worker.hata_sinyali.connect(self.hata_goster)
        self.worker.start()

    def kanal_analizi_yap(self, networks):
        kanallar = {1: 0, 2:0, 3:0, 4:0, 5:0, 6: 0, 7:0, 8:0, 9:0, 10:0, 11: 0, 12:0, 13:0}
        total_24 = 0
        
        for item in networks:
            if item[4] == "2.4 GHz":
                try:
                    ch = int(item[2])
                    if ch in kanallar: 
                        kanallar[ch] += 1
                        total_24 += 1
                except: pass
        
        if total_24 == 0:
            self.lbl_oneri.setText("Çevrede 2.4 GHz ağ bulunamadı veya Wi-Fi kapalı.")
            return

        ana_kanallar = {1: kanallar.get(1,0), 6: kanallar.get(6,0), 11: kanallar.get(11,0)}
        en_iyi_kanal = min(ana_kanallar, key=ana_kanallar.get)
        yogunluk = ana_kanallar[en_iyi_kanal]
        
        msg = f"<span style='color:#e67e22; font-weight:bold;'>ANALİZ SONUCU:</span> Çevrede {total_24} adet 2.4GHz ağ tespit edildi.<br>"
        
        if yogunluk == 0:
            msg += f"✅ <b>TAVSİYE:</b> Kanal <b style='font-size:12pt; color:#2ecc71;'>{en_iyi_kanal}</b> tamamen boş! Modeminizi bu kanala sabitleyiniz."
        else:
            msg += f"ℹ️ <b>TAVSİYE:</b> Kanal <b style='font-size:12pt; color:#f1c40f;'>{en_iyi_kanal}</b> en az yoğunluğa sahip. ({yogunluk} ağ var)"
            
        self.lbl_oneri.setText(msg)

    def sonuc_goster(self, networks):
        if not self.chk_auto.isChecked():
            self.btn_tara.setEnabled(True)
            self.btn_tara.setText("📡 Şimdi Tara")
        
        self.table.setRowCount(0)
        self.kanal_analizi_yap(networks)
        
        for ssid, signal, chan, sec, band, bssid, in_use in networks:
            r = self.table.rowCount()
            self.table.insertRow(r)
            
            ssid_item = QTableWidgetItem(ssid)
            if in_use:
                ssid_item.setForeground(QColor("#2ecc71"))
                font = ssid_item.font()
                font.setBold(True)
                ssid_item.setFont(font)
                ssid_item.setText(f"{ssid} (Bağlı)")
            self.table.setItem(r, 0, ssid_item)
            
            w_bar = QWidget()
            l_bar = QHBoxLayout(w_bar)
            l_bar.setContentsMargins(5, 5, 5, 5)
            l_bar.setAlignment(Qt.AlignmentFlag.AlignCenter)
            
            pbar = QProgressBar()
            pbar.setValue(signal)
            pbar.setTextVisible(True)
            pbar.setFormat(f"%{signal}")
            pbar.setFixedHeight(16)
            
            if signal > 70: col = "#2ecc71"
            elif signal > 40: col = "#f1c40f"
            else: col = "#e74c3c"
            
            pbar.setStyleSheet(f"""
                QProgressBar {{
                    background-color: #444;
                    border: 1px solid #666;
                    border-radius: 3px;
                    color: white;
                    text-align: center;
                    font-size: 10px;
                    font-weight: bold;
                }}
                QProgressBar::chunk {{
                    background-color: {col};
                    border-radius: 3px;
                }}
            """)
            
            l_bar.addWidget(pbar)
            self.table.setCellWidget(r, 1, w_bar)
            
            c_item = QTableWidgetItem(chan); c_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter); self.table.setItem(r, 2, c_item)
            b_item = QTableWidgetItem(band); b_item.setTextAlignment(Qt.AlignmentFlag.AlignCenter); self.table.setItem(r, 3, b_item)
            
            sec_short = sec.replace("WPA1", "").replace("WPA2", "WPA2").strip()
            self.table.setItem(r, 4, QTableWidgetItem(sec_short[:15]))
            self.table.setItem(r, 5, QTableWidgetItem(bssid))

        if not networks:
            self.table.setRowCount(1)
            self.table.setItem(0, 0, QTableWidgetItem("Ağ bulunamadı."))

    def hata_goster(self, msg):
        if not self.chk_auto.isChecked():
            self.btn_tara.setEnabled(True)
            self.btn_tara.setText("📡 Şimdi Tara")
        self.lbl_oneri.setText(f"<b style='color:red'>Hata:</b> {msg}")