1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
import subprocess import re import curses import time def calculate_distance(signal_dBm): """ Calcula la distancia estimada en metros basándose en la potencia de la señal en dBm. """ C = 40 # Parámetro de ajuste, que puede variar según el entorno try: # Extraer el primer valor de señal si hay más de uno signal_dBm_value = float(signal_dBm.split(' / ')[0].replace(' dBm', '').strip()) # La fórmula para calcular la distancia en metros distance = 10 ** ((-signal_dBm_value - C) / 20.0) return distance except ValueError: return float('inf') # Si no se puede calcular, retorna infinito def get_wifi_info(): try: # Ejecutar el comando system_profiler command = ['system_profiler', 'SPAirPortDataType'] result = subprocess.check_output(command, universal_newlines=True) # Usar una expresión regular para encontrar la sección de "Other Local Wi-Fi Networks" match = re.search(r'Other Local Wi-Fi Networks:\n((?:\s+.+\n)+)', result) if match: # Extraer la sección de interés other_networks_section = match.group(1).strip() # Eliminar secciones que empiezan con 'awdl0:' filtered_lines = [] skip_block = False for line in other_networks_section.splitlines(): if line.strip().startswith("awdl0:"): skip_block = True if not skip_block: filtered_lines.append(line) if line.strip() == "": skip_block = False # Unir las líneas filtradas en una sola cadena filtered_section = "\n".join(filtered_lines).strip() # Expresión regular para extraer los datos de la red network_info_re = re.compile( r'(?P<SSID>[^\:]+):\s*PHY Mode:\s*(?P<mode>\S+)\s*' r'Channel:\s*(?P<channel>[^\n]+)\s*' r'(?:Country Code:\s*(?P<country_code>[^\n]+)\s*)?' r'Network Type:\s*(?P<network_type>[^\n]+)\s*' r'Security:\s*(?P<security>[^\n]+)\s*' r'(?:Signal / Noise:\s*(?P<signal>[^\n]+)\s*)?' ) # Buscar todas las redes en la sección extraída networks = [] for match in network_info_re.finditer(filtered_section): ssid = match.group('SSID').strip() mode = match.group('mode').strip() channel = match.group('channel').strip() country_code = match.group('country_code').strip() if match.group('country_code') else "N/A" network_type = match.group('network_type').strip() security = match.group('security').strip() signal = match.group('signal').strip() if match.group('signal') else "N/A" # Calcular la distancia distance = calculate_distance(signal) networks.append((ssid, mode, channel, country_code, network_type, security, signal, distance)) return networks else: print("No se encontró la sección de 'Other Local Wi-Fi Networks'.") return [] except subprocess.CalledProcessError as e: print(f"Error al ejecutar el comando system_profiler: {e}") return [] except Exception as e: print(f"Error inesperado: {e}") return [] def draw_distance_lines(stdscr, networks, line_length=100, scale=0.5): """Dibuja una línea que representa las distancias de las redes Wi-Fi.""" curses.curs_set(0) # Ocultar el cursor stdscr.nodelay(1) # Hacer que getch() sea no bloqueante curses.start_color() # Iniciar la capacidad de color curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) # Rojo curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK) # Amarillo curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLACK) # Blanco max_width = curses.COLS start_row = 0 for i, (ssid, mode, channel, country_code, network_type, security, signal, distance) in enumerate(networks): info_to_display = (f"SSID: {ssid} | Mode: {mode} | Channel: {channel} | " f"Country: {country_code} | Type: {network_type} | " f"Security: {security} | Signal: {signal} | Distance: {distance:.2f} meters") # Verificar si el texto cabe en la línea if len(info_to_display) > max_width: info_to_display = info_to_display[:max_width] stdscr.addstr(start_row + i, 0, info_to_display, curses.color_pair(3)) # Limitar la distancia a un rango razonable if distance == float('inf'): scaled_distance = 0 # Si la distancia es infinita, no dibujar 'X' else: scaled_distance = min(int(distance * scale), line_length - 1) # Crear la línea con la 'X' en la posición calculada line = [' '] * line_length line[scaled_distance] = 'X' stdscr.addstr(start_row + i, len(info_to_display), ''.join(line), curses.color_pair(1)) # Rojo stdscr.refresh() def main(stdscr): while True: stdscr.clear() stdscr.addstr(0, 0, "Escaneando redes Wi-Fi...", curses.color_pair(3)) networks = get_wifi_info() draw_distance_lines(stdscr, networks, line_length=100, scale=0.5) # Escala ajustada a 0.5 time.sleep(5) # Esperar 5 segundos antes de volver a escanear # Ejecutar el escaneo y obtener detalles con curses curses.wrapper(main) |