-
-
Save bridger/83fc2e9c60fd07d925b0bec80c47acab to your computer and use it in GitHub Desktop.
bluez scanner for broadcast listening, only once per second
This file contains 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
# BLE scanner based on https://github.com/adamf/BLE/blob/master/ble-scanner.py | |
# JCS 06/07/14 | |
# https://github.com/pauloborges/bluez/blob/master/tools/hcitool.c for lescan | |
# https://kernel.googlesource.com/pub/scm/bluetooth/bluez/+/5.6/lib/hci.h for opcodes | |
# https://github.com/pauloborges/bluez/blob/master/lib/hci.c#L2782 for | |
# functions used by lescan | |
import binascii | |
import sys | |
import struct | |
import bluetooth._bluetooth as bluez | |
LE_META_EVENT = 0x3e | |
LE_PUBLIC_ADDRESS = 0x00 | |
LE_RANDOM_ADDRESS = 0x01 | |
LE_SET_SCAN_PARAMETERS_CP_SIZE = 7 | |
OGF_LE_CTL = 0x08 | |
OCF_LE_SET_SCAN_PARAMETERS = 0x000B | |
OCF_LE_SET_SCAN_ENABLE = 0x000C | |
OCF_LE_CREATE_CONN = 0x000D | |
LE_ROLE_MASTER = 0x00 | |
LE_ROLE_SLAVE = 0x01 | |
# these are actually subevents of LE_META_EVENT | |
EVT_LE_CONN_COMPLETE = 0x01 | |
EVT_LE_ADVERTISING_REPORT = 0x02 | |
EVT_LE_CONN_UPDATE_COMPLETE = 0x03 | |
EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE = 0x04 | |
# Advertisment event types | |
ADV_IND = 0x00 | |
ADV_DIRECT_IND = 0x01 | |
ADV_SCAN_IND = 0x02 | |
ADV_NONCONN_IND = 0x03 | |
ADV_SCAN_RSP = 0x04 | |
def returnnumberpacket(pkt): | |
myInteger = 0 | |
multiple = 256 | |
for c in pkt: | |
myInteger += struct.unpack("B", c)[0] * multiple | |
multiple = 1 | |
return myInteger | |
def returnstringpacket(pkt): | |
myString = "" | |
for c in pkt: | |
myString += "%02x" % struct.unpack("B", c)[0] | |
return myString | |
def printpacket(pkt): | |
for c in pkt: | |
sys.stdout.write("%02x " % struct.unpack("B", c)[0]) | |
def get_packed_bdaddr(bdaddr_string): | |
packable_addr = [] | |
addr = bdaddr_string.split(':') | |
addr.reverse() | |
for b in addr: | |
packable_addr.append(int(b, 16)) | |
return struct.pack("<BBBBBB", *packable_addr) | |
def packed_bdaddr_to_string(bdaddr_packed): | |
return ':'.join('%02x' % i for i in struct.unpack("<BBBBBB", bdaddr_packed[::-1])) | |
def hci_enable_le_scan(sock): | |
hci_toggle_le_scan(sock, 0x01) | |
def hci_disable_le_scan(sock): | |
hci_toggle_le_scan(sock, 0x00) | |
def hci_toggle_le_scan(sock, enable): | |
cmd_pkt = struct.pack("<BB", enable, 0x00) | |
bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE, cmd_pkt) | |
def start_scan(sock): | |
SCAN_TYPE = 0x01 | |
INTERVAL = 0x1 | |
WINDOW = 0x1 | |
OWN_TYPE = 0x01 | |
FILTER = 0x00 # all advertisements, not just whitelisted devices | |
# interval and window are uint_16, so we pad them with 0x0 | |
cmd_pkt = struct.pack("<BBBBBBB", SCAN_TYPE, 0x0, INTERVAL, 0x0, WINDOW, OWN_TYPE, FILTER) | |
bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS, cmd_pkt) | |
hci_enable_le_scan(sock) | |
flt = bluez.hci_filter_new() | |
bluez.hci_filter_all_events(flt) | |
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT) | |
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt) | |
def parse_event(sock): | |
while True: | |
pkt = sock.recv(255) | |
ptype, event, plen = struct.unpack("BBB", pkt[:3]) | |
if event == LE_META_EVENT: | |
subevent, = struct.unpack("B", pkt[3]) | |
pkt = pkt[4:] | |
if subevent == EVT_LE_ADVERTISING_REPORT: | |
# print "advertising report" | |
num_reports = struct.unpack("B", pkt[0])[0] | |
for report in range(0, num_reports): | |
address = packed_bdaddr_to_string( | |
pkt[3:9]) | |
if address != '04:a3:16:9a:f3:22': | |
continue | |
rssi = struct.unpack("b", pkt[-1]) | |
rest_bin = pkt[9:-2] | |
rest = binascii.b2a_hex(rest_bin).decode('utf-8') | |
return [address, rssi, rest] | |
def main(): | |
dev_id = 0 | |
try: | |
sock = bluez.hci_open_dev(dev_id) | |
print "ble thread started" | |
except: | |
print "error accessing bluetooth device..." | |
sys.exit(1) | |
blescan.start_scan(sock) | |
while True: | |
beacon = blescan.parse_event(sock) | |
print beacon | |
print "----------" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment