El cálculo de la distancia es una estimación.
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 |
import subprocess import re import asyncio from bleak import BleakScanner from prettytable import PrettyTable # RSSI de referencia a 1 metro (usualmente entre -59 y -65 dBm) RSSI_REFERENCE = -59 # Factor de propagación (n) PROPAGATION_CONSTANT = 2 def calculate_wifi_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: signal_dBm_value = float(signal_dBm.split(' / ')[0].replace(' dBm', '').strip()) distance = 10 ** ((-signal_dBm_value - C) / 20.0) return distance except ValueError: return float('inf') # Si no se puede calcular, retorna infinito def calculate_ble_distance(rssi, reference=RSSI_REFERENCE, n=PROPAGATION_CONSTANT): """ Calcula la distancia estimada en metros basándose en el RSSI. """ return 10 ** ((reference - rssi) / (10 * n)) def get_wifi_info(): wifi_data = [] try: command = ['system_profiler', 'SPAirPortDataType'] result = subprocess.check_output(command, universal_newlines=True) match = re.search(r'Other Local Wi-Fi Networks:\n((?:\s+.+\n)+)', result) if match: other_networks_section = match.group(1).strip() 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 filtered_section = "\n".join(filtered_lines).strip() 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*' r'(?:Transmit Rate:\s*(?P<transmit_rate>[^\n]+)\s*)?' r'(?:MCS Index:\s*(?P<mcs>[^\n]+)\s*)?' ) for match in network_info_re.finditer(filtered_section): ssid = match.group('SSID').strip() signal = match.group('signal').strip() distance = calculate_wifi_distance(signal) signal_dBm = signal.split(' / ')[0].strip() wifi_data.append([ssid, signal_dBm, distance]) except subprocess.CalledProcessError as e: print(f"Error al ejecutar el comando system_profiler: {e}") except Exception as e: print(f"Error inesperado: {e}") return wifi_data async def scan_for_devices(): print("Escaneando dispositivos BLE...") devices = await BleakScanner.discover() return devices async def get_ble_info(): ble_data = [] devices = await scan_for_devices() if not devices: print("No se encontraron dispositivos BLE.") else: for device in devices: distance = calculate_ble_distance(device.rssi) ble_data.append([device.name or "Unknown", device.rssi, distance]) return ble_data async def display_info(): while True: # Obtener información de WiFi wifi_data = get_wifi_info() # Obtener información de BLE ble_data = await get_ble_info() # Crear una tabla para mostrar los datos table = PrettyTable() table.field_names = ["Nombre", "Potencia (dBm)", "Distancia (metros)"] # Agregar datos de WiFi for row in wifi_data: table.add_row(row) # Agregar datos de BLE for row in ble_data: table.add_row(row) # Ordenar las filas por la distancia (de menor a mayor) table.sortby = "Distancia (metros)" table.reversesort = False # Limpiar la pantalla antes de imprimir la nueva tabla (opcional) print("\033c", end="") # Imprimir la tabla print(table) # Esperar 3 segundos antes de la próxima actualización await asyncio.sleep(3) # Ejecutar el escaneo if __name__ == '__main__': asyncio.run(display_info()) |