-
Notifications
You must be signed in to change notification settings - Fork 6
/
blescan.py
153 lines (128 loc) · 5.1 KB
/
blescan.py
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
'''
Scan for Bluetooth LE devices in the area.
This is a slightly altered version of `blescan.py` from the IanHarvey/bluepy repository.
'''
#!/usr/bin/env python
import argparse
import binascii
import os
import sys
from bluepy import btle
from database import XsensDOTDatabase
if os.getenv('C', '1') == '0':
ANSI_RED = ''
ANSI_GREEN = ''
ANSI_YELLOW = ''
ANSI_CYAN = ''
ANSI_WHITE = ''
ANSI_OFF = ''
else:
ANSI_CSI = "\033["
ANSI_RED = ANSI_CSI + '31m'
ANSI_GREEN = ANSI_CSI + '32m'
ANSI_YELLOW = ANSI_CSI + '33m'
ANSI_CYAN = ANSI_CSI + '36m'
ANSI_WHITE = ANSI_CSI + '37m'
ANSI_OFF = ANSI_CSI + '0m'
def dump_services(dev):
services = sorted(dev.services, key=lambda s: s.hndStart)
for s in services:
print ("\t%04x: %s" % (s.hndStart, s))
if s.hndStart == s.hndEnd:
continue
chars = s.getCharacteristics()
for i, c in enumerate(chars):
props = c.propertiesToString()
h = c.getHandle()
if 'READ' in props:
val = c.read()
if c.uuid == btle.AssignedNumbers.device_name:
string = ANSI_CYAN + '\'' + \
val.decode('utf-8') + '\'' + ANSI_OFF
elif c.uuid == btle.AssignedNumbers.device_information:
string = repr(val)
else:
string = '<s' + binascii.b2a_hex(val).decode('utf-8') + '>'
else:
string = ''
print ("\t%04x: %-59s %-12s %s" % (h, c, props, string))
while True:
h += 1
if h > s.hndEnd or (i < len(chars) - 1 and h >= chars[i + 1].getHandle() - 1):
break
try:
val = dev.readCharacteristic(h)
print ("\t%04x: <%s>" %
(h, binascii.b2a_hex(val).decode('utf-8')))
except btle.BTLEException:
break
class ScannerDatabase(btle.DefaultDelegate):
def __init__(self, opts):
btle.DefaultDelegate.__init__(self)
self.opts = opts
self.xsens_db = XsensDOTDatabase()
def handleDiscovery(self, dev, isNewDev, isNewData):
if isNewDev:
status = "new"
elif isNewData:
if self.opts.new:
return
status = "update"
else:
if not self.opts.all:
return
status = "old"
if dev.rssi < self.opts.sensitivity:
return
print (' Device (%s): %s (%s), %d dBm %s' %
(status,
ANSI_WHITE + dev.addr + ANSI_OFF,
dev.addrType,
dev.rssi,
('' if dev.connectable else '(not connectable)'))
)
for (sdid, desc, val) in dev.getScanData():
if sdid in [8, 9]:
if dev.addr[:8] == "d4:ca:6e": # Is an Xsens DOT device
self.xsens_db.add_device(dev.addr, None, dev.rssi)
print ('\t' + desc + ': \'' + ANSI_CYAN + val + ANSI_OFF + '\'')
else:
if dev.addr[:8] == "d4:ca:6e": # Is an Xsens DOT device
self.xsens_db.add_device(dev.addr, None, dev.rssi)
print ('\t' + desc + ': <' + val + '>')
if not dev.scanData:
print ('\t(no data)')
print
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--hci', action='store', type=int, default=0,
help='Interface number for scan')
parser.add_argument('-t', '--timeout', action='store', type=int, default=4,
help='Scan delay, 0 for continuous')
parser.add_argument('-s', '--sensitivity', action='store', type=int, default=-128,
help='dBm value for filtering far devices')
parser.add_argument('-d', '--discover', action='store_true',
help='Connect and discover service to scanned devices')
parser.add_argument('-a', '--all', action='store_true',
help='Display duplicate adv responses, by default show new + updated')
parser.add_argument('-n', '--new', action='store_true',
help='Display only new adv responses, by default show new + updated')
parser.add_argument('-v', '--verbose', action='store_true',
help='Increase output verbosity')
arg = parser.parse_args(sys.argv[1:])
btle.Debugging = arg.verbose
scanner = btle.Scanner(arg.hci).withDelegate(ScannerDatabase(arg))
print (ANSI_RED + "Scanning for devices..." + ANSI_OFF)
devices = scanner.scan(arg.timeout)
if arg.discover:
print (ANSI_RED + "Discovering services..." + ANSI_OFF)
for d in devices:
if not d.connectable or d.rssi < arg.sensitivity:
continue
print (" Connecting to", ANSI_WHITE + d.addr + ANSI_OFF + ":")
dev = btle.Peripheral(d)
dump_services(dev)
dev.disconnect()
print
if __name__ == "__main__":
main()