Last active
November 28, 2023 17:36
-
-
Save aminnj/39fcb48f5ff1398fd7c6b51d00f620ca to your computer and use it in GitHub Desktop.
Get RSSI of nearby bluetooth peripherals using CoreBluetooth in python
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 rich | |
from Foundation import NSObject, NSRunLoop, NSDefaultRunLoopMode, NSDate, NSArray | |
from CoreBluetooth import CBCentralManager, CBCentralManagerStatePoweredOn, CBUUID | |
import time | |
state = {} | |
# Create a delegate to handle CoreBluetooth events | |
class MyCentralManagerDelegate(NSObject): | |
def __init__(self): | |
self.central_manager = None | |
def startScanning(self): | |
self.central_manager.scanForPeripheralsWithServices_options_([], None) | |
print("Bluetooth is ON. Scanning for peripherals...") | |
def centralManagerDidUpdateState_(self, central): | |
if central.state() == CBCentralManagerStatePoweredOn: | |
self.startScanning() | |
else: | |
print("Bluetooth is either off or unavailable") | |
def centralManager_didDiscoverPeripheral_advertisementData_RSSI_(self, central, peripheral, advertisementData, rssi): | |
timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) | |
identifier = str(peripheral.identifier()) | |
name = peripheral.name() | |
# https://domoticx.com/bluetooth-company-identifiers/ | |
# https://stackoverflow.com/questions/42140636/extract-data-from-kcbadvdatamanufacturerdata-on-swift | |
manufacturer_data = advertisementData.get("kCBAdvDataManufacturerData", None) | |
# print(advertisementData) | |
manufacturer_id = None | |
node_id = None | |
node_state = None | |
voltage = None | |
packet_counter = None | |
ibeacon_data = None | |
if manufacturer_data: | |
# L is 0x4c - 76 - apple | |
# https://stackoverflow.com/questions/18906988/what-is-the-ibeacon-bluetooth-profile/19040616#19040616 | |
# https://stackoverflow.com/questions/36092497/ibeacons-understanding-minor-major-and-uuid | |
if b"L\x00\x02\x15" in bytes(manufacturer_data): | |
uuid = manufacturer_data[4:20].hex() | |
major = (int.from_bytes(manufacturer_data[20:22], byteorder="big")) | |
minor = (int.from_bytes(manufacturer_data[22:23], byteorder="big")) | |
ibeacon_data = dict(uuid=uuid, major=major, minor=minor) | |
manufacturer_id = int.from_bytes(manufacturer_data[:2], byteorder="little") | |
node_id = int.from_bytes(manufacturer_data[2:4], byteorder="little") | |
node_state = int.from_bytes(manufacturer_data[4:5], byteorder="little") | |
voltage = int.from_bytes(manufacturer_data[5:6], byteorder="little") | |
packet_counter = int.from_bytes(manufacturer_data[6:9], byteorder="little") | |
# NOTE: | |
# Can't get bdaddr for devices this way. | |
# `identifier` is a uuid that the device running the script assigned to the peripheral | |
# If another device runs this script, it'll get a different `identifier` for that same peripheral | |
# But I have not confirmed if the the same device will always get the same `identifier` for the same peripheral | |
state[identifier] = dict(timestamp=time.time(), | |
name=name, | |
rssi=rssi, | |
manufacturer_id=manufacturer_id, | |
node_id=node_id, | |
node_state=node_state, | |
voltage=voltage, | |
packet_counter=packet_counter, | |
ibeacon_data=ibeacon_data, | |
) | |
# print(state) | |
central_manager_delegate = MyCentralManagerDelegate.new() | |
central_manager = CBCentralManager.alloc().initWithDelegate_queue_(central_manager_delegate, None) | |
central_manager_delegate.central_manager = central_manager | |
# Start the central manager | |
while True: | |
run_loop = NSRunLoop.currentRunLoop() | |
central_manager_delegate.startScanning() | |
# does 5 seconds of scanning | |
# probably at some point want to scan continuously and update `state` | |
run_loop.runUntilDate_(NSDate.dateWithTimeIntervalSinceNow_(5)) | |
print(len(state)) | |
rich.print(state) | |
time.sleep(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment