Contenidos
Enlaces interesantes sobre el tema
- https://www.jesusninoc.com/08/27/obtener-un-listado-en-python-de-los-dispositivos-bluetooth-cercanos
- https://www.jesusninoc.com/08/27/escanear-dispositivos-bluetooth-y-caracteristicas-escribibles-desde-python
- https://www.jesusninoc.com/08/27/escanear-dispositivos-bluetooth-caracteristicas-escribibles-y-el-atributo-handle-de-cada-caracteristicas-desde-python/
- https://www.jesusninoc.com/08/27/crear-una-aplicacion-para-iphone-que-permita-recibir-mensajes-por-bluetooth/
Programa en Python que calcula la distancia estimada a la que se encuentra un dispositivo BLE (Bluetooth Low Energy), analiza información sobre el dispostivo BLE y envía un mensaje al dispositivo cercano con características escribibles (usando handle)
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 |
import asyncio from bleak import BleakScanner, BleakClient from bleak.backends.device import BLEDevice # Reemplaza esto con el mensaje que deseas enviar MESSAGE = "Hola" # 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_distance(rssi, reference=RSSI_REFERENCE, n=PROPAGATION_CONSTANT): """ Calcula la distancia estimada en metros basada en el RSSI. :param rssi: La intensidad de la señal recibida en dBm. :param reference: RSSI de referencia a 1 metro (en dBm). :param n: Factor de propagación. :return: La distancia estimada en metros. """ if rssi == 0: return float('inf') # La distancia no puede calcularse si RSSI es 0 return 10 ** ((reference - rssi) / (10 * n)) async def scan_for_devices(): """Escanea dispositivos BLE y devuelve una lista de dispositivos encontrados.""" print("Escaneando dispositivos BLE...") devices = await BleakScanner.discover() return devices async def connect_and_send_message(device, message): """Conecta al dispositivo BLE y envía un mensaje a cada handle de características que soporten escritura.""" try: async with BleakClient(device) as client: print(f"Conectado a {device.name or 'Desconocido'} ({device.address})") try: services = await client.get_services() for service in services: print(f"Servicio: {service.uuid}") for characteristic in service.characteristics: properties = characteristic.properties print(f" Característica: {characteristic.uuid} - Propiedades: {properties}") if "write" in properties: try: # Utilizar el handle para enviar el mensaje handle = characteristic.handle await client.write_gatt_char(handle, message.encode('utf-8')) print(f"Mensaje '{message}' enviado a la característica con handle {handle}.") except Exception as e: print(f"Error al enviar mensaje a la característica con handle {handle}: {e}") except Exception as e: print(f"Error al obtener servicios: {e}") except Exception as e: print(f"Error al conectar con el dispositivo {device.name or 'Desconocido'}: {e}") async def main(): devices = await scan_for_devices() if not devices: print("No se encontraron dispositivos BLE.") return for device in devices: # Extraer RSSI directamente del objeto device rssi = device.rssi # Suponemos que el dispositivo BLE proporciona el RSSI correctamente # Calcular distancia estimada distance = calculate_distance(rssi) # Formatear la salida distance_str = f"{distance:.2f} metros" if distance != float('inf') else "No disponible" name = device.name or "Desconocido" address = device.address or "Desconocido" # Información del dispositivo print(f"\n-------------------------------") print(f"Dispositivo encontrado: {name}") print(f" Dirección (MAC): {address}") print(f" RSSI: {rssi} dBm - Distancia estimada: {distance_str}") # Información adicional sobre el dispositivo if 'advertisement' in device.metadata: advertisement = device.metadata['advertisement'] if 'manufacturer_data' in advertisement: manufacturer_data = advertisement['manufacturer_data'] for company_id, data in manufacturer_data.items(): print(f" Datos del fabricante (Company ID {company_id}): {data.hex()}") if 'local_name' in advertisement: print(f" Nombre local: {advertisement['local_name']}") if 'tx_power_level' in advertisement: print(f" Nivel de potencia TX: {advertisement['tx_power_level']} dBm") # Conectar y enviar mensaje await connect_and_send_message(device, MESSAGE) # Separador para cada dispositivo print("\n" + "-"*50 + "\n") # Ejecutar el escaneo y el envío de mensajes asyncio.run(main()) |