Created
June 10, 2025 15:06
-
-
Save blainerothrock/a10b8796d613e770755d17fe8fc248b7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import CoreBluetooth | |
/* | |
This Swift script scans for Bluetooth devices and prints information about the active Bluetooth adapter. | |
It uses the CoreBluetooth framework to manage Bluetooth operations and the system_profiler command to fetch adapter details. | |
To compile & run: | |
```bash | |
swiftc -framework CoreBluetooth main.swift -o BLEScanner | |
./BLEScanner | |
``` | |
Tested with Swift Version 6.1.2 (swiftlang-6.1.2.1.2 clang-1700.0.13.5) & macOS 15.5 (24F74) on Apple M2 Pro | |
Example output (third party Bluetooth device): | |
```txt | |
./BLEScanner | |
📡 Fetching active Bluetooth adapter info... | |
Bluetooth: | |
Bluetooth Controller: | |
Address: 00:25:BF:71:62:24 | |
State: On | |
Chipset: THIRD_PARTY_DONGLE | |
Discoverable: Off | |
Firmware Version: v13083 c13083 | |
Product ID: 0x4A11 | |
Supported services: 0x392039 < HFP AVRCP A2DP HID Braille LEA AACP GATT SerialPort > | |
Transport: PCIe | |
Vendor ID: 0x004C (Apple) | |
Bluetooth is powered on. Starting scan. | |
``` | |
example output (Apple Bluetooth device): | |
```txt | |
./BLEScanner | |
📡 Fetching active Bluetooth adapter info... | |
Bluetooth: | |
Bluetooth Controller: | |
Address: 5C:E9:1E:99:EB:EF | |
State: On | |
Chipset: BCM_4388 | |
Discoverable: Off | |
Firmware Version: 22.5.542.2777 | |
Product ID: 0x4A11 | |
Supported services: 0x392039 < HFP AVRCP A2DP HID Braille LEA AACP GATT SerialPort > | |
Transport: PCIe | |
Vendor ID: 0x004C (Apple) | |
Not Connected: | |
8BitDo Lite gamepad: | |
Address: E4:17:D8:CF:9B:15 | |
Vendor ID: 0x045E | |
Product ID: 0x02E0 | |
Firmware Version: 9.0.3 | |
Minor Type: Gamepad | |
MX Anywhere 3S: | |
Address: D8:74:CD:2F:11:40 | |
Minor Type: Mouse | |
MX Anywhere 3S: | |
Address: D6:2F:DE:72:0F:12 | |
Minor Type: Mouse | |
MX Keys Mini: | |
Address: D1:5A:18:16:6B:FB | |
Minor Type: Keyboard | |
MX KEYS S MAC: | |
Address: DF:CC:F5:0A:90:3A | |
Minor Type: Keyboard | |
Pro Controller: | |
Address: E4:17:D8:78:0C:62 | |
Vendor ID: 0x057E | |
Product ID: 0x2009 | |
Firmware Version: 0.0.1 | |
Minor Type: Gamepad | |
Bluetooth is powered on. Starting scan. | |
Discovered: IOTWF790 - RSSI: -82 | |
Discovered: Unknown - RSSI: -72 | |
Discovered: M720 Triathlon - RSSI: -47 | |
Discovered: M720 Triathlon - RSSI: -47 | |
Discovered: Unknown - RSSI: -69 | |
Discovered: Unknown - RSSI: -71 | |
Discovered: Unknown - RSSI: -71 | |
Discovered: Unknown - RSSI: -65 | |
Discovered: Alex's Whoop - RSSI: -87 | |
Discovered: wee-adv - RSSI: -46 | |
Discovered: wee-adv - RSSI: -46 | |
```` | |
*/ | |
func printAdapterInfo() { | |
print("📡 Fetching active Bluetooth adapter info...\n") | |
let task = Process() | |
task.executableURL = URL(fileURLWithPath: "/usr/sbin/system_profiler") | |
task.arguments = ["SPBluetoothDataType"] | |
let pipe = Pipe() | |
task.standardOutput = pipe | |
task.standardError = pipe | |
do { | |
try task.run() | |
let data = pipe.fileHandleForReading.readDataToEndOfFile() | |
if let output = String(data: data, encoding: .utf8) { | |
print(output) | |
} | |
} catch { | |
print("Failed to fetch adapter info: \(error)") | |
} | |
} | |
class Scanner: NSObject, CBCentralManagerDelegate { | |
var centralManager: CBCentralManager! | |
override init() { | |
super.init() | |
centralManager = CBCentralManager(delegate: self, queue: nil) | |
} | |
func centralManagerDidUpdateState(_ central: CBCentralManager) { | |
if central.state == .poweredOn { | |
print("Bluetooth is powered on. Starting scan.") | |
centralManager.scanForPeripherals(withServices: nil, options: nil) | |
} else { | |
print("Bluetooth not available: \(central.state.rawValue)") | |
} | |
} | |
func centralManager(_ central: CBCentralManager, | |
didDiscover peripheral: CBPeripheral, | |
advertisementData: [String : Any], | |
rssi RSSI: NSNumber) { | |
print("Discovered: \(peripheral.name ?? "Unknown") - RSSI: \(RSSI)") | |
} | |
} | |
// Keep the program alive | |
printAdapterInfo() | |
let scanner = Scanner() | |
RunLoop.main.run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment