def cmd_list_devices(self, *args): try: self.last_scan = ScanDelegate() scanner = Scanner().withDelegate(self.last_scan) print('Listing Bluetooth LE devices in range for 5 minutes.' 'Press CTRL+C to stop searching.') print('{: <5} {: <30} {: <12}'.format('ID', 'Name', 'Mac address')) print('{: <5} {: <30} {: <12}'.format('--', '----', '-----------')) scanner.scan(350) except KeyboardInterrupt: print('\n') except RuntimeError as e: logger.error('Problem with the Bluetooth adapter : {}'.format(e)) return False
def find_temp_sensors(sensors): TempSensor._scanning_lock.acquire() logger.debug('Scanning for devices') scanner = Scanner().withDelegate(ScanDelegate()) try: devices = scanner.scan(10.0) if sensors is None: sensors = {} for device in devices: if device.addr in sensors: continue name = '' if device.getValueText(9): name = device.getValueText(9) elif device.getValueText(8): name = device.getValueText(8) logger.debug('Device name: ' + name) if 'SensorTag' in name: logger.info('Found SensorTag with address: ' + device.addr) sensors[device.addr] = SensorTag(device) elif 'MetaWear' in name: logger.info('Found MetaWear with address: ' + device.addr) sensors[device.addr] = MetaWear(device) logger.debug('Finished scanning for devices') TempSensor._scanning_lock.release() if len(sensors) == 0: raise NoTagsFoundException('No sensors found!') except BTLEException as e: scanner.stop() logger.warn('Got exception ' + e.message) TempSensor._scanning_lock.release() return sensors
def find_port(self): """Detects Ganglion board MAC address If more than 1 around, will select first. Needs root privilege. """ print("Try to detect Ganglion MAC address. " "NB: Turn on bluetooth and run as root for this to work!" "Might not work with every BLE dongles.") scan_time = 5 print("Scanning for 5 seconds nearby devices...") # From bluepy example class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): if isNewDev: print("Discovered device: " + dev.addr) elif isNewData: print("Received new data from: " + dev.addr) scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(scan_time) nb_devices = len(devices) if nb_devices < 1: print("No BLE devices found. Check connectivity.") return "" else: print("Found " + str(nb_devices) + ", detecting Ganglion") list_mac = [] list_id = [] for dev in devices: # "Ganglion" should appear inside the "value" associated # to "Complete Local Name", e.g. "Ganglion-b2a6" for (adtype, desc, value) in dev.getScanData(): if desc == "Complete Local Name" and value.startswith("Ganglion"): list_mac.append(dev.addr) list_id.append(value) print("Got Ganglion: " + value + ", with MAC: " + dev.addr) break nb_ganglions = len(list_mac) if nb_ganglions < 1: print("No Ganglion found ;(") raise OSError('Cannot find OpenBCI Ganglion MAC address') if nb_ganglions > 1: print("Found " + str(nb_ganglions) + ", selecting first") print("Selecting MAC address " + list_mac[0] + " for " + list_id[0]) return list_mac[0]
def getTag(self): """Scans for BT LE devices and returns the choosen keywords""" self.count = 0 scanner = Scanner().withDelegate(DefaultDelegate()) devices = scanner.scan(self.scanTimeout) for dev in devices: if dev.addr == self.address.lower(): self.count = 1 if self.count > 0: self.count = 0 return self.found else: return self.missing
def connect(strip, scanTimeout=2, reconnectAttempts=1, maxAttempts=10): # Max attempts reached if reconnectAttempts > maxAttempts: print("Failed to connect after %d attempts" % maxAttempts) return try: # Scanning for devices print("Scanning for devices (%d / %d)" % (reconnectAttempts, maxAttempts)) scanner = Scanner() devices = scanner.scan(scanTimeout) for device in devices: # Only connect to Nuimos if device.connectable and device.getValueText(9) == "Nuimo": # Init Nuimo class nuimo = Nuimo(device.addr) nuimo.set_delegate(NuimoDelegate(nuimo, strip)) # Connect to Nuimo print("Trying to connect to %s." % device.addr) nuimo.connect() nuimo.displayLedMatrix(LedMatrixString().getRaspberry(), 5) print("Connected successfully to %s." % device.addr) # Reset reconnect attempts on successfull connect reconnectAttempts = 0 while True: nuimo.waitForNotifications() return # Found no Nuimo print("Couldn't find a Nuimo.") connect(strip, scanTimeout + 1, reconnectAttempts + 1) except BTLEException: print("Failed to connect to %s. Make sure to:\n 1. Run program as root (For Scanning and the Strip)\n 2. Disable the Bluetooth device: hciconfig hci0 down\n 3. Enable the Bluetooth device: hciconfig hci0 up\n 4. Enable BLE: btmgmt le on\n" % nuimo.macAddress) connect(strip, scanTimeout + 1, reconnectAttempts + 1) except KeyboardInterrupt: print("Program aborted.") return
def _findRileyLink(self): scanner = Scanner() found = None self.logger.debug("Scanning for RileyLink") retries = 10 while found is None and retries > 0: retries -= 1 for result in scanner.scan(1.0): if result.getValueText(7) == RILEYLINK_SERVICE_UUID: self.logger.debug("Found RileyLink") found = result.addr try: with open(RILEYLINK_MAC_FILE, "w") as stream: stream.write(result.addr) except IOError: self.logger.warning("Cannot store rileylink mac radio_address for later") break if found is None: raise PacketRadioError("Could not find RileyLink") return found
def scan_devs(self): func_name = inspect.stack()[0][3] logging.debug('%s start BLE scan', func_name) adapter = Scanner(0) devices = adapter.scan(10.0) logging.debug('%s found %d devices', func_name, len(devices)) for d in devices: logging.debug('%s inspecting device %s', func_name, d.addr) for (tag, desc, value) in d.getScanData(): logging.debug('%s tag=%s desc=%s value=%s', func_name, tag, desc, value) if tag == 9 and value in self.supported_devs: logging.debug('%s compatible device @%s', func_name, d.addr) if d.addr not in self.devices: self.devices[d.addr] = d logging.info('%s added device @%s to ble_devices', func_name, d.addr) self.cons[d.addr] = Peripheral(d.addr, 'random') self.sendDevice(d.addr) logging.info('%s connected to device @%s', func_name, d.addr) logging.debug('%s devices=%s', func_name, self.devices) logging.debug('%s cons=%s', func_name, self.cons) logging.debug('%s done BLE scan', func_name)
def __init__(self): DefaultDelegate.__init__(self) self.lastseq = None self.lasttime = datetime.fromtimestamp(0) # devにはアドバタイズパケットの情報が詰まっている。ScanEntryクラス def handleDiscovery(self, dev, isNewDev, isNewData): if dev.addr == '30:ae:a4:0e:4f:12': #print('welcome Advertise Data') advdata = dev.getScanData() #print(advdata) for (at, at_desc, ad) in advdata: if at == 0xff: # ESP側でセットしたManifacturer Specific Data mdata = int(ad, 16) # AD部分には16進文字列が格納されているため数値に変換 stick1_lr = (mdata & 0x000000ff00000000) >> 0x20 stick1_ud = (mdata & 0x00000000ff000000) >> 0x18 stick2_lr = (mdata & 0x0000000000ff0000) >> 0x10 stick2_ud = (mdata & 0x000000000000ff00) >> 0x08 print(stick1_lr, stick1_ud, stick2_lr, stick2_ud) # Scannerインスタンスを生成するとスキャン開始 # withDelegateでデバイス見つけたときのハンドラーを渡しておくと呼んでくれる。 scanner = Scanner().withDelegate(ScanDelegate()) try: while True: scanner.scan(0.05) except KeyboardInterrupt: pass
if device.get('state') == actions.OFF_STATE: if device.get( 'previous_state') == actions.OFF_STATE: device['state'] = actions.BRIGHTEN_STATE if device.get( 'previous_state') == actions.DARKEN_STATE: device['state'] = actions.BRIGHTEN_STATE if device.get('previous_state' ) == actions.BRIGHTEN_STATE: device['state'] = actions.DARKEN_STATE else: actions.toggle(device) scanner = Scanner().withDelegate(ScanDelegate()) while True: devices = scanner.scan(1.0) if ble_devices.AIRER.get("state") == 1: # lets see if its been on for 8 hours and if so turn it off lastUpdated = ble_devices.AIRER.get("lastUpdated", datetime) timeSinceTurnedOn = datetime.now() - lastUpdated if timeSinceTurnedOn.seconds >= (8 * (60 * 60)): # turn off print("Timer has been on for %d hours and %d minutes" % ((timeSinceTurnedOn.seconds / 60 / 60), ((timeSinceTurnedOn.seconds) / 60) % 60)) actions.toggle(ble_devices.AIRER) if ble_devices.LIVING_ROOM_LIGHTS.get("state") > 0: print("lights triggered") actions.changeLights(ble_devices.LIVING_ROOM_LIGHTS)
def scan_devs(self, timeout=8, scan_type='active', sort='rssi'): """LE devices scanning scan_type - Indicate the type of LE scan:active, passive, adv or features. """ if scan_type == 'adv': return scanner = Scanner(self.devid).withDelegate(LEDelegate()) #print("[Debug] timeout =", timeout) # scan() 返回的 devs 是 dictionary view。 if scan_type == 'active': # Active scan 会在 LL 发送 SCAN_REQ PDU logger.warning( 'Before doing an active scan, make sure you spoof your BD_ADDR.' ) logger.info('LE active scanning on %s with timeout %d sec\n' % \ (blue('hci%d'%self.devid), timeout)) devs = scanner.scan(timeout) elif scan_type == 'passive': logger.info('LE passive scanning on %s with timeout %d sec\n' % \ (blue('hci%d'%self.devid), timeout)) devs = scanner.scan(timeout, passive=True) else: logger.error('Unknown LE scan type') return if sort == 'rssi': devs = list(devs) # 将 dictionary view 转换为 list devs.sort(key=lambda d: d.rssi) for dev in devs: print('Addr: ', blue(dev.addr.upper())) print('Addr type: ', blue(dev.addrType)) print('Connectable:', green('True') if dev.connectable else red('False')) print("RSSI: %d dB" % dev.rssi) print("General Access Profile:") for (adtype, desc, val) in dev.getScanData(): # 打印当前 remote LE dev 透露的所有 GAP 数据(AD structure)。 # # 如果 bluepy.scan() 执行的是 active scan,那么这些 GAP 数据 # 可能同时包含 AdvData 与 ScanRspData。其中 AdvData 由 remote LE # dev 主动返回,ScanRspData 由 remote BLE dev 响应 SCAN_REQ 返回。 # # 虽然 LL 分开定义了 Advertising PDUs (ADV_IND, ADV_DIRECT_IND...) # 和 Scanning PDUs (SCAN_REQ, SCAN_RSP)。但它们分别包含的 AdvData # 与 ScanRspData 到了 HCI 层都被放在了 HCI_LE_Advertising_Report # event 中。HCI_LE_Advertising_Report 的 Event_Type 标识了这些数 # 据具体来源于哪个 LL 层的 PDU。另外 ScanRspData 与 AdvData 的格式 # 完全相同,都是 GAP 协议标准定义的 AD structure。 # # 在 LL 定义的 Advertising PDUs 中 ADV_DIRECT_IND 一定不会包含 # AdvData。其余的 ADV_IND,ADV_NONCONN_IND 以及 ADV_SCAN_IND 都 # 可能包含 AdvData。 # # 另外 getScanData() 返回的 desc 还可以通过 ScanEntry.getDescription() # 单独获取;val 还可以通过 ScanEntry.getValueText() 单独获取; # adtype 表示当前一条 GAP 数据(AD structure)的类型。 print('\t' + desc + ': ', end='') if adtype == COMPLETE_16_BIT_SERVICE_CLS_UUID_LIST: for uuid in val.split(','): print() if len(uuid) == 36: # 这里拿到的是完整的 128-bit uuid,但我们需要 16-bit uuid。 print('\t\t' + blue(uuid[4:8])) else: print('\t\t' + blue(uuid)) continue elif adtype == MANUFACTURER_SPECIFIC_DATA: val = bytes.fromhex(val) if len(val) > 2: print() print( '\t\tCompany ID:', '0x%04x' % int.from_bytes(val[0:2], 'little', signed=False)) print('\t\tData:', val[2:]) else: print(val) continue print(val) print("\n")
from bluepy.btle import Scanner print "Scan ..." scanner = Scanner(0) devices = scanner.scan(3) for d in devices: print str(d.addr) + " - " + str(d.addrType) print "Done"
# Vulnerability Details #https://github.com/jasondoyle/Komfy-Switch-Wifi-Password-Disclosure # Author: Jason Doyle @_jasondoyle # Komfy Switch with Camera wifi password disclosure exploit script import re, base64 from bluepy.btle import Scanner from gattlib import GATTRequester #lookup table to unscramble base64Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" # '=' used for padding komfy64Alphabet = "qazwersdfxcvbgtyhnmjklpoiu5647382910+/POIKLMJUYTGHNBVFREWSDCXZAQ$" # '$' used for padding scanner = Scanner() devices = scanner.scan(5.0) bAddr = "" for dev in devices: if "6c:72:20" in dev.addr and dev.getValueText(1) and dev.getValueText( 7) and dev.getValueText(9): bAddr = dev.addr print "[+] Komfy switch found: %s (%s), RSSI=%d dB" % ( dev.addr, dev.addrType, dev.rssi) if not bAddr: print "No Komfy switches found" sys.exit(1) req = GATTRequester(bAddr.encode('ascii', 'ignore'), False, 'hci0') req.connect(True, 'public', 'none', 0, 78) #request SSID
import time from bluepy.btle import UUID, Peripheral from bluepy.btle import Scanner, DefaultDelegate class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleNotification(self, cHandle, data): print "inside notification" print "Heart rate:", ord(data[1]), "Energy=" ,int(binascii.b2a_hex((data[::-1])[0:2]),16) # This script was tested on ubuntu 14.04 # To solve the endianess problem reverse the # string to find exact value devices = Scanner() # Scanner Object temp=devices.scan(10) # Start Scan try: for dev in temp: if dev.getScanData()[3][2] == "mr. singh": # Check for the target BLE device name if dev.connectable: p = Peripheral(dev.addr, "random") p.setDelegate(ScanDelegate()) # Create internal Object of scandelegate class to handle the notifications except (RuntimeError, TypeError, NameError): print "Device not found" exit(1) ################### Check for the Services and its characteristics ################# print p.getServices()[0] print p.getServices()[1] print p.getServices()[2] Heart_Rate_Measurement = p.getServiceByUUID(0x180D).getCharacteristics()[0] Body_Sensor_Location = p.getServiceByUUID(0x180D).getCharacteristics()[1]
def main(): scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(10.0) tags = [] for dev in devices: completeLocalName = dev.getValueText(COMPLETE_LOCAL_NAME) if completeLocalName == "CC2650 SensorTag": print("Connecting to {0} {1} ({2}), RSSI={3} dB".format( completeLocalName, dev.addr, dev.addrType, dev.rssi)) tags.append(sensortag.SensorTag(dev.addr)) for i in range(0, len(tags)): tags[i].magnetometer.enable() time.sleep(3.0) endTime = time.time() + 10 data = len(tags) * [[]] ''' while time.time() < endTime: #for i in range(0, len(tags)): data.append(tags[0].magnetometer.read()) ''' print('Calculating Offsets...') pos_dict = cali_funcs.parse_input(CALI_FILE) pos_m = [] h = [] for i in range(CALI_MAG_POSITION): for p in range(CALI_POS_SAMPLES): pos_m.append(pos_dict['MagPos' + str(i)]) h.append(pos_dict['MagOrien' + str(i)]) #print(pos_m) while i < CALI_OFFSET_SAMPLES: for index in range(len(tags)): #data[index].append(tags[index].magnetometer.read()) data[index].append([20, 20, 20]) i = i + 1 offsets = len(tags) * [[0, 0, 0]] for i in range(len(tags)): offsets[i] = cali_funcs.cali_offset(data[i]) print('Calibrating...') data = [] for i in range(len(tags)): data.append([]) for pos in range(CALI_MAG_POSITION): print('Place Mag at position ', pos) tmp = input('Press Enter to continue') for index in range(len(tags)): for i in range(CALI_POS_SAMPLES): #data[index].append(tags[index].magnetometer.read()) data[index].append([ 20 + (index + i) * 10, 20 + (index + i) * 10, 20 + 10 * (index + i) ]) cali_para = [] #print(pos_m) for i in range(len(tags)): cali_para.append([]) pos_l = pos_dict['Sensor' + str(i)].copy() cali_para[i] = cali_funcs.calibrateSensor(data[i], pos_m, h, pos_l, CALI_ITER, offsets[i]).copy() print('Calibration Finished') tmp = input('Press Enter to continue') '''
# recupere le numero du controleur if args.device == "hci0": index = 0 elif args.device == "hci1": index = 1 elif args.device == "hci2": index = 2 elif args.device == "hci3": index = 3 else: print("device error (hci0 a hci3)") scanner = Scanner(index).withDelegate(ScanDelegate()) try: devices = scanner.scan(int(args.timeout)) except: # pylint: disable-msg=W0702 print( "Erreur dans le scan le controleur est probablement occupe essayer un autre " ) else: file_dat = "/tmp/MiFlora_rssi_" + args.antenne + ".dat" # print ("file_dat : " + file_dat) file_out = open(file_dat, "w") for dev in devices: # print ("%s,%s,(%s),%d;" % (args.antenne,dev.addr, dev.addrType, dev.rssi)) for (adtype, desc, value) in dev.getScanData(): if desc == "Complete Local Name": print("%s;%s;%s;%s;%d;%s," % (args.id, args.antenne, dev.addr, dev.addrType, \ dev.rssi, value))
#!/usr/bin/env python # import os import bluepy.btle as ble from bluepy.btle import Scanner, DefaultDelegate class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): if isNewDev: print("Discovered device"), dev.addr elif isNewData: print("Received new data from", dev.addr) scanner = Scanner().withDelegate(ScanDelegate()) devs = scanner.scan(2) for dev in devs: if dev.addr == "ac:23:3f:25:a1:06": print(dev.addr, "acquired data:") print(dev.getScanData())
def main(): #Scan for Bluetooth devices for 2 seconds scanner = Scanner().withDelegate(ScanDelegate()) scanner.scan(200.0)
▒██░█▀ ▓▓█ ░██░▒▓▓▄ ▄██▒▓██ █▄ ▒██░ ▒▓█ ▄ ░▓█ ░██ ▓▓█ ░██░▓██▒ ▐▌██▒░ ▓██▓ ░ ▒▓█ ▄ ▒██▀▀█▄ ░▓█ ▀█▓▒▒█████▓ ▒ ▓███▀ ░▒██▒ █▄░██████▒░▒████▒ ░▓█▒░██▓▒▒█████▓ ▒██░ ▓██░ ▒██▒ ░ ░▒████▒░██▓ ▒██▒ ░▒▓███▀▒░▒▓▒ ▒ ▒ ░ ░▒ ▒ ░▒ ▒▒ ▓▒░ ▒░▓ ░░░ ▒░ ░ ▒ ░░▒░▒░▒▓▒ ▒ ▒ ░ ▒░ ▒ ▒ ▒ ░░ ░░ ▒░ ░░ ▒▓ ░▒▓░ ▒░▒ ░ ░░▒░ ░ ░ ░ ▒ ░ ░▒ ▒░░ ░ ▒ ░ ░ ░ ░ ▒ ░▒░ ░░░▒░ ░ ░ ░ ░░ ░ ▒░ ░ ░ ░ ░ ░▒ ░ ▒░ ░ ░ ░░░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ░░ ░ ░░░ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ''' print(a) print_banner() scanner = Scanner() log.info(f"Scannig around for BLE.. Wait for {SCAN_TIME} seconds") devices = scanner.scan(SCAN_TIME) log.info(f"Scannig done. Found {len(devices)}") buckles = [] if len(devices) == 0: log.warn("Where are you dude ? :X Maybe increase scan time ?") exit() c = 0 c2 = 0 totallen = len(devices) with log.progress('Taking closer look to found devices') as progress: for dev in devices: time.sleep(0.2) for (adtype, desc, value) in dev.getScanData():
while True: confirm = input("You entered " + device_name + ". Would you like to use this name?") if "y" in confirm.lower(): break else: device_name = input( "Please name your phone (e.g. \"Oncology Attending\".\n\n") # Initial scan x = input( "I will now scan nearby BLE devices.\n\nMake sure your phone has Bluetooth enabled and near the RPI.\n\nThis will take 10 seconds.\n\nPress ENTER to continue..." ) scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(10) for dev in devices: #print("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)) for (adtype, desc, value) in dev.getScanData(): #print(" %s = %s" % (desc, value)) first_scan.append(dev.addr) if dev.addr not in signal_strength: signal_strength[dev.addr] = dev.rssi x = input( "Ready for the second scan. This will take 10 seconds.\n\nTurn off your Bluetooth and press ENTER to continue..." ) # Second scan, with Bluetooth off scanner = Scanner().withDelegate(ScanDelegate())
DefaultDelegate.__init__(self) def HandleDiscovery(self,dev,new_dev,new_dat): if new_dev: pass if new_dat: pass scanner = Scanner().withDelegate(ScanDelegate()) time_diff = 0 first_time = 1 while 1: try: devices = scanner.scan(0.35) ## print("Amount of Devices = "+str(len(devices))) for ii in devices: print(ii.addr) print("Device %s, RSSI=%d dB" % (ii.addr,ii.rssi)) if first_time == 1: first_time = 0 pass else: time_diff = time.time()-time_prev time_prev = time.time() rssi_prev = ii.rssi continue except:
def main(): # uuid definition targetDevice = "" targetUUID = UUID("08590f7e-db05-467e-8757-72f6f66666d4") # targetUUID = UUID(0x2a2b) serviceUUID = UUID("e20a39f4-73f5-4bc4-a12f-17d1ad666661") # scanning for Bluetooth LE device # P.S. root permission is needed print "scanning started..." scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(5) print "\n\nscanning completed...\n found %d device(s)\n" % len(devices) for dev in devices: print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi) for (adtype, desc, value) in dev.getScanData(): print " %s = %s" % (desc, value) try: p = Peripheral(dev.addr, "random") ch = p.getCharacteristics(uuid=targetUUID) if len(ch) > 0: print "the desired target found. the address is", dev.addr targetDevice = dev.addr except: # print "Unexpected error:", sys.exc_info()[0] print "Unable to connect" print " " finally: p.disconnect() # scanning completed, now continue to connect to device if targetDevice == "": # the target is not found. end. print "no target was found." else: # the target found, continue to subscribe. print "\n\nthe target device is ", targetDevice print "now try to subscribe..." try: # try to get the handle first p = Peripheral(targetDevice, "random") p.setDelegate(NotificationDelegate()) # svc = p.getServiceByUUID(serviceUUID) ch = p.getCharacteristics(uuid=targetUUID)[0] # svc.getCharacteristics(targetUUID)[0] handle = ch.getHandle() print handle ch.write(struct.pack('<bb', 0x01, 0x00)) # ch.write(bytes('aa', 'utf-8')) # p.writeCharacteristic(handle, struct.pack('<bb', 0x01, 0x00), True) print # Main loop while True: if p.waitForNotifications(5): # handleNotification() was called continue print "Waiting..." # Perhaps do something else here # except: # print "Unexpected error:", sys.exc_info()[0] finally: p.disconnect()
class BLERelay( DefaultDelegate): ######################## ## BLE SCANNING ######################## def __init__(self): self.packets_sent = 0 self.scanning = False self.scanner = None self.sock = None self.sock_recv_thread = None self.current_service_info = None self.connected_peripherals = list() self.isConnecting = False self.connected_scan_entry: ScanEntry = None self.ble_timeout = 2.0 self.autoconnect = True self.readable_services = [AssignedNumbers.device_information, AssignedNumbers.generic_access, AssignedNumbers.generic_attribute] # List of characteristics UUIDs that hav failed. Created dynamically such that they won't be read a second time self.failing_characteristics: typing.List[UUID] = list() DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): """ A BLE signal has been received. The content is part of the dev parameter """ self.relay_ble_advertisement(dev) def start_ble_scanning(self): """ Start the BLE Scanner """ # Setup BLE Scanner self.scanner = Scanner().withDelegate(self) self.scanning = True t = Thread(target=self.scan_forever, name="ble_scanning") t.start() def scan_forever(self): """ Scan for BLE signals forever. Uses a short scannning time and a Timer to restart scanning quickly """ while self.scanning: try: # Scan for scan_time. Then scan again DBG("Start scanning", logLevel=LogLevel.DEBUG) scan_time = 1.0 devices = self.scanner.scan(scan_time, passive=False) connectable_devices = [dev for dev in devices if dev.connectable and not next((d for d in self.connected_peripherals if d == dev.addr), None)] DBG("Scan finished. Discovered {} devices".format(len(devices))) # Connect on a different thread if self.autoconnect and len(connectable_devices) > 0: DBG("Connecting to device", logLevel=LogLevel.DEBUG) # Connect to one device and read info before performing a scan again self.connected_scan_entry = connectable_devices[0] self.read_info_from_ble_device(self.connected_scan_entry) elif len(connectable_devices) == 0: DBG("No connectable devices found", logLevel=LogLevel.DEBUG) else: DBG("Postponing connection. Already connecting", logLevel=LogLevel.DEBUG) except Exception as e: DBG("Scan error", logLevel=LogLevel.ERR) logging.exception(e) DBG("Stopping BLE Scan", logLevel=LogLevel.DEBUG) #asyncio.create_task #asyncio.run_coroutine_threadsafe(self.connect_to_devices_async(connectable_devices), loop=asyncio.get_event_loop()) def read_info_from_ble_device(self, dev: ScanEntry): peripheral = self.connect_to_ble_device(dev) if peripheral: services = self.read_services_from_peripheral(peripheral, dev) self.read_characteristics(peripheral, dev, services) self.disconnect_from_peripheral(peripheral) def connect_to_ble_device(self, dev: ScanEntry) -> Peripheral : """ Connect to a BLE device. This is used to discover services running on this device """ DBG("Connecting to {}".format(dev.addr), logLevel=LogLevel.DEBUG) ## Try connecting try: self.connected_peripherals.append(dev.addr) peripheral = Peripheral(dev, timeout=self.ble_timeout) return peripheral except Exception as e: DBG("Connecting to {} failed".format(dev.addr), logLevel=LogLevel.ERR) logging.exception(e) return None def reconnect_to_device(self, dev: ScanEntry, old_peripheral: Peripheral) -> Peripheral: try: # old_peripheral.disconnect() time.sleep(0.5) DBG("Reconnecting to {}".format(dev.addr)) peripheral = Peripheral(dev, timeout=3.0) return peripheral except Exception as e: DBG("Reconnecting to {} failed".format(dev.addr), logLevel=LogLevel.ERR) logging.exception(e) return None def disconnect_from_peripheral(self, peripheral: Peripheral): try: if peripheral: peripheral.disconnect(timeout=self.ble_timeout) except Exception as e: DBG("Disconnecting failed", logLevel=LogLevel.ERR) # DBG(e, logLevel=LogLevel.ERR) def read_services_from_peripheral(self, peripheral: Peripheral, dev: ScanEntry) -> typing.List[Service]: ## Try getting servicex try: services = peripheral.getServices() self.relay_discovered_services(peripheral, services) return services except Exception as e: DBG("Getting services from {} failed".format(dev.addr), logLevel=LogLevel.ERR) logging.exception(e) services = list() return services def read_characteristics(self, peripheral: Peripheral, dev: ScanEntry, services:typing.List[Service]): if len(services) > 0: #Discovered services DBG("Discovered services {}".format([s.uuid.getCommonName() for s in services]), logLevel=LogLevel.INFO) for s in services: try: DBG("Accessing service: {}".format(s.uuid.getCommonName())) characteristics = s.getCharacteristics() DBG("Discovered characteristics:\n\t{}".format([c.uuid.getCommonName() for c in characteristics])) ## characteristics_info = [(c, b'') for c in characteristics] if s.uuid in self.readable_services: self.read_value_for_charateristics(characteristics, s, peripheral, dev) else: characteristics_info = [(c, b'') for c in characteristics] self.relay_service_information(dev, s, characteristics_info) ## self.relay_service_information(peripheral, s, characteristics_info) except Exception as e: DBG("Accessing service failed {}".format(s.uuid.getCommonName()), logLevel=LogLevel.ERR) logging.exception(e) # peripheral = self.reconnect_to_device(dev, old_peripheral=peripheral) # if not peripheral: # break def read_value_for_charateristics(self, characteristics: typing.List[Characteristic], service: Service, peripheral: Peripheral, device: ScanEntry): characteristics_info = list() for c in characteristics: try: # Check if Extended properties DBG("Characteristic {} Properties {}".format(c, c.propertiesToString()), logLevel=LogLevel.DEBUG) if c.properties & Characteristic.props["EXTENDED"]: DBG("Uses extended properties", logLevel=LogLevel.DEBUG) characteristics_info.append((c, b'')) continue if c.supportsRead() and not c.uuid in self.failing_characteristics: value = peripheral.readCharacteristic(c.valHandle, timeout=self.ble_timeout) characteristics_info.append((c, value)) DBG("Read {} and received {}".format(c.uuid.getCommonName(), value)) else: characteristics_info.append((c, b'')) except Exception as e: DBG("Could not read characteristic {} - {}".format(c.uuid.getCommonName(), c.uuid.binVal), logLevel=LogLevel.DEBUG) # DBG(e.with_traceback(), logLevel=LogLevel.ERR) characteristics_info.append((c, b'')) # peripheral = self.reconnect_to_device(device, old_peripheral=peripheral) # if not peripheral: # break self.relay_service_information(device, service, characteristics_info) def handleNotification(self, cHandle, data): """ BTLE Peripheral delegate callback """ DBG("Received notification from cHandle: {} with data {}".format(cHandle, data), logLevel=LogLevel.INFO) ######################## ## ZEROCONF ######################## def remove_service(self, zeroconf, type, name): """ A service has been removed with mDNS/DNS-SD """ if self.current_service_info and self.current_service_info.name == name: # Service removed. Disconnect self.disconnected_from_socket() DBG("Service %s removed" % (name,)) def add_service(self, zeroconf, type, name): """ A service has been resolved with mDNS / DNS-SD """ info = zeroconf.get_service_info(type, name) #print("Service %s added, service info: %s" % (name, info)) # Found service. Connect to it self.connect_to_service(info) def connect_to_service(self, info): """ Connect to a service that has been detected """ self.current_service_info = info self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) addr_string = socket.inet_ntop(socket.AF_INET, info.addresses[0]) #print("Service IP address {}".format(addr_string)) service_address = (addr_string, info.port) DBG("Connecting to {}".format(service_address), logLevel=LogLevel.DEBUG) try: self.sock.settimeout(5.0) self.sock.connect(service_address) # Start receiving thread t = Thread(target=self.receive_control_commands, name="sock_receiving") t.start() except Exception as e: DBG("Socket connection failed", logLevel=LogLevel.ERR) logging.exception(e) self.disconnected_from_socket() def disconnected_from_socket(self): """ Called when the socket disconnected. Clearing up the internal state """ DBG("Stopping...", logLevel=LogLevel.DEBUG) self.sock.close() self.scanning = False self.sock = None DBG("Cleaning up...") self.current_service_info = None # Clear the lists for scanned peripherals self.connected_peripherals = list() def receive_control_commands(self): """ Loop to receive data from the socket. Run in it's own thread """ DBG("Waiting for incomming messages", logLevel=LogLevel.DEBUG) while self.sock: try: header = self.sock.recv(5) if header: DBG("Received incoming message header ", header) # Received header message_type = header[0] message_length = int.from_bytes(header[1:], byteorder="little") # Read the full message message = self.sock.recv(message_length) self.control_command_received(message_type, message) except Exception as e: # Sockets can timeout. No worries to get an exception here # DBG("Error occured while receiving from socket", logLevel=LogLevel.ERR) # DBG(e, logLevel=LogLevel.ERR) continue def control_command_received(self, message_type: bytes, message: bytes): """ The control commands have been received. They will be parsed """ DBG("Received message\n type: {}, message: {}".format(message_type,message)) # 0xfe is the message type for standard control commands if message_type == 0xef: # Decode message to JSON json_message = json.loads(message) # { # scanning: true | false, autoconnect: true | false # } DBG("Received control command \n{}".format(json_message), logLevel=LogLevel.DEBUG) scanning = json_message["scanning"] if scanning == True: self.start_ble_scanning() elif scanning == False: self.scanning = False autoconnect = json_message["autoconnect"] if autoconnect == True : self.autoconnect = True elif autoconnect == False: self.autoconnect = False ######################## ## RELAY BLE INFO ######################## ## Sending BLE Packets def relay_ble_advertisement(self, scanEntry: ScanEntry): """ Send the BLE packet to the connected service running on iOS """ ### Message format # 1 byte type - 4 bytes message length - message ### name = scanEntry.getValueText( ScanEntry.COMPLETE_LOCAL_NAME) if not name: name = scanEntry.getValueText( ScanEntry.SHORT_LOCAL_NAME) # services_16 = scanEntry.getValueText(ScanEntry.INCOMPLETE_16B_SERVICES) # services_32 = scanEntry.getValueText(ScanEntry.INCOMPLETE_32B_SERVICES) # services_128 = scanEntry.getValueText(ScanEntry.INCOMPLETE_128B_SERVICES) # print("Services 16B: \n\t{}\nServices 32B: \n\t{}\nServices 128B: \n\t{}".format(services_16, services_32 , services_128 )) DBG("Raw Data: {}".format(scanEntry.rawData), logLevel=LogLevel.DEBUG) raw_data_hex = "" if scanEntry.rawData: raw_data_hex = scanEntry.rawData.hex() packet_content = { "manufacturerDataHex": scanEntry.getValueText(ScanEntry.MANUFACTURER), "macAddress": scanEntry.addr, "rssi": scanEntry.rssi, "name": name, "flags": scanEntry.getValueText( ScanEntry.FLAGS), "addressType": scanEntry.addrType, "connectable": scanEntry.connectable, "rawData": raw_data_hex, #"scanData": {tag: scanEntry.getValueText(k) for k, tag in scanEntry.dataTags.items()} } # Check for additional content in this advertisement # Get service UUIDs serviceUUIDs = list() if scanEntry.getValueText(ScanEntry.INCOMPLETE_16B_SERVICES): serviceUUIDs.append(scanEntry.getValueText(ScanEntry.INCOMPLETE_16B_SERVICES)) if scanEntry.getValueText(ScanEntry.INCOMPLETE_32B_SERVICES): serviceUUIDs.append(scanEntry.getValueText(ScanEntry.INCOMPLETE_32B_SERVICES)) if scanEntry.getValueText(ScanEntry.INCOMPLETE_128B_SERVICES): serviceUUIDs.append(scanEntry.getValueText(ScanEntry.INCOMPLETE_128B_SERVICES)) if scanEntry.getValueText(ScanEntry.COMPLETE_16B_SERVICES): serviceUUIDs.append(scanEntry.getValueText(ScanEntry.COMPLETE_16B_SERVICES)) if scanEntry.getValueText(ScanEntry.COMPLETE_32B_SERVICES): serviceUUIDs.append(scanEntry.getValueText(ScanEntry.COMPLETE_32B_SERVICES)) if scanEntry.getValueText(ScanEntry.COMPLETE_128B_SERVICES): serviceUUIDs.append(scanEntry.getValueText(ScanEntry.COMPLETE_128B_SERVICES)) if len(serviceUUIDs) > 0: packet_content["serviceUUIDs"] = serviceUUIDs # Get service data if scanEntry.getValueText(ScanEntry.SERVICE_DATA_16B): packet_content["serviceData16Bit"] = scanEntry.getValueText(ScanEntry.SERVICE_DATA_16B) if scanEntry.getValueText(ScanEntry.SERVICE_DATA_32B): packet_content["serviceData32Bit"] = scanEntry.getValueText(ScanEntry.SERVICE_DATA_32B) if scanEntry.getValueText(ScanEntry.SERVICE_DATA_128B): packet_content["serviceData128Bit"] = scanEntry.getValueText(ScanEntry.SERVICE_DATA_128B) DBG("Encoding json: ", packet_content) json_packet = json.dumps(packet_content).encode() # Message type for advertisements is 0 self.send_packet_over_socket(packet_type=0, packet_data=json_packet) def relay_discovered_services(self, device: Peripheral, services:typing.List[ Service]): """ Relay a packet with all services discovered for a peripheral """ packet_content = { "macAddress": device.addr, "services": [{ "uuid": s.uuid.binVal.hex(), "commonName": s.uuid.getCommonName() } for s in services] } json_packet = json.dumps(packet_content).encode() self.send_packet_over_socket(packet_type=1, packet_data=json_packet) def relay_service_information(self, device: ScanEntry, service: Service, characteristic_info: typing.List[typing.Tuple[Characteristic, bytes]]): packet_content = { "macAddress": device.addr, "service": { "uuid": service.uuid.binVal.hex(), "commonName": service.uuid.getCommonName() }, "characteristics": [{ "serviceUUID": service.uuid.binVal.hex(), "uuid": c[0].uuid.binVal.hex(), "commonName": c[0].uuid.getCommonName(), "value": c[1].hex() } for c in characteristic_info] } json_packet = json.dumps(packet_content).encode() self.send_packet_over_socket(packet_type=2, packet_data=json_packet) def send_packet_over_socket(self, packet_type: int, packet_data: bytes): """ Send information over the connected socket Parameters: packet_type (int): The integer representing the packet type that should be sent (e.g. 0 for a BLE advertisment) packer_data (bytes): The data for a packet that should be sent """ message_length = len(packet_data).to_bytes(4, byteorder="little") message_type = packet_type.to_bytes(1, byteorder="little") sendable_packet = message_type + message_length + packet_data DBG("Sending packet with content\n\t{}".format(packet_data.decode())) if not self.sock: # No socket available return try: self.packets_sent += 1 # print("Sending no. {} at: {}".format(self.packets_sent, datetime.datetime.now())) self.sock.send(sendable_packet) except Exception as e: DBG("Sending over socket failed", logLevel=LogLevel.ERR) DBG("Reason: {}".format(e), logLevel=LogLevel.ERR) self.disconnected_from_socket()
nomeDoArquivo = raw_input("\nArquivo: ") # sem extensão nomeDoArquivo = "dados/experimento8 (obstruido)/" + nomeDoArquivo + ".txt" arquivo = open(nomeDoArquivo, 'w') rssiList = [] distancias = [] timeout, start_time = time.time() + 600, datetime.now() count = 0 while True: if (count >= 100): break # index is the hci port number of blutooth device, you can consult on terminal with command $ "rfkill" # timeout is a timer o scanner on while loop, it works as a delay scanner = Scanner(1).withDelegate(ScanDelegate()) devices = scanner.scan(timeout = 3) for dev in devices: if (dev.addr == "c8:fd:19:37:2b:0a"): count += 1 imprime(dev.rssi) rssiList.append(dev.rssi) end_time = datetime.now() arquivo.write(str(rssiList)) arquivo.write('\n') arquivo.write(str(distancias)) arquivo.write('\n') arquivo.write('Experiment time: {} '.format(end_time - start_time)) arquivo.close() print('\n Experiment time: {} '.format(end_time - start_time))
#スキャンしてデバイス見つけたときのハンドラー class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) self.lastseq = None self.lasttime = datetime.fromtimestamp(0) def handleDiscovery(self, dev, isNewDev, isNewData): if dev.addr == ADDR_BSTICK: # ESP32 からだったら print("try connect to ", dev.addr) con = Connection(ADDR_BSTICK) print("connected.") con.setDelegate(NotifyDelegate()) while True: if con.waitForNotifications(10.0): continue print("wait..") # Scannerインスタンスを生成するとスキャン開始 # withDelegateでデバイス見つけたときのハンドラーを渡しておくと呼んでくれる。 scanner = Scanner().withDelegate(ScanDelegate()) try: while True: print("scanning..") scanner.scan(1) sleep(1) except KeyboardInterrupt: pass
def main(): scanner = Scanner().withDelegate(ScanDelegate()) device_list = scanner.scan(5) # scan for 5 seconds for device in device_list: if (device.addr.lower() == DH_ADDRESS.lower()): print("Target device host discovered!") # RSSI = Received Signal Strength Indicator print("Device %s (%s), RSSI=%d dB" % (device.addr, device.addrType, device.rssi)) scan_data = device.getScanData() device_name = scan_data[2][2] auth_service_uuid = scan_data[4][2] print(device_name) print(auth_service_uuid) #for (adtype,desc,value) in device.getScanData(): # print("\t%s = %s" % (desc, value)) try: device = Peripheral(DH_ADDRESS) device.setMTU(520) device.setDelegate(PeripheralDelegate()) print("Successfully connected to device host") auth_service = device.getServiceByUUID(auth_service_uuid) auth_char = auth_service.getCharacteristics()[0] # read authentication characteristic state auth_char_val = auth_char.read() #print(auth_char_val) if (auth_char_val.decode() == '0x15'): # BLE_CHAR_AUTH_REQ print("# Device host ready to receive authentication ticket") #auth_ticket = { 'sercret':1, 'public':2 ,'signature':3} #auth_ticket = "{'secret': qqqqqqqqqqqqqqaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss, 'public': {'dh_id' : uuid, 'dh_addr' : addr, 'owner_id' : gw_id, 'access_rights' : 'Rx', 'ticket_lifetime': 3600},'signature': sig}" s_auth_ticket = str(auth_ticket).replace("b\'", "") print(s_auth_ticket) msg_header = "0x50" #msg_payload = str(auth_ticket).encode() #msg = msg_header.encode() + msg_payload #msg = msg[0:100] if ((len(s_auth_ticket) + HEADER_SIZE) > MAX_MSG_SIZE): print("Message size exceeds maximum capacity. Fragmenting data...") fragments = dataFragment(s_auth_ticket) for frag in fragments: msg = msg_header.encode() + frag.encode() print(msg) #print(len(msg)) auth_char.write(msg) time.sleep(0.5) else: print("Packet does not exceed maximum capacity") #auth_char.write(msg) #else: # catch other responses here # such as if device not ready, wait and do authentication later # < TODO > # print("# Something went wrong...") """ while True: if p.waitForNotifications(1.0): # handleNotification() was called continue print "Waiting..." # Perhaps do something else here """ finally: device.disconnect()
print(json.dumps(self.parseData(val))) exit() def isTemperature(self, addr, sdid, val): if sdid != 22: return False if len(val) != 30: return False return True def parseData(self, val): bytes = [int(val[i:i + 2], 16) for i in range(0, len(val), 2)] return { 'timestamp': datetime.now().astimezone().replace(microsecond=0).isoformat(), 'mac': ":".join(["{:02X}".format(bytes[i]) for i in range(2, 8)]), 'temperature': (bytes[8] * 16 + bytes[9]) / 10, 'humidity': bytes[10], 'battery_percent': bytes[11], 'battery_volt': (bytes[12] * 16 + bytes[13]) / 1000, 'count': bytes[14], } scanner = Scanner().withDelegate(ScanDelegate()) scanner.scan(10.0, passive=True)
client.connect(broker_address, 1883, 60) # create a delegate class to receive the BLE broadcast packets class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) # when this python script discovers a BLE broadcast packet, print a message with the device's MAC address def handleDiscovery(self, dev, isNewDev, isNewData): if mac == dev.addr: client.publish("room_presence/" + place + "/" + dev.addr, dev.rssi) print "device", dev.addr, dev.rssi # create a scanner object that sends BLE broadcast packets to the ScanDelegate scanner = Scanner().withDelegate(ScanDelegate()) # start the scanner and keep the process running #scanner.start() while True: print "Still running..." devs = scanner.scan(10, passive=True) found = 0 for x in devs: if x.addr == mac: found = 1 if found == 0: print "reset" client.publish("room_presence/" + place + "/" + mac, "-99")
def ble_rescan(tb_gateway): # Scan for known devices class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): if isNewDev: print("Discovered BT device:", dev.addr) elif isNewData: print("Received new data from:", dev.addr) known_devices_found = False # Deactivate and clear existing devices before re-scanning for dev, dev_data in known_devices.items(): for scanned, scanned_data in dev_data["scanned"].items(): tb_name = scanned_data["tb_name"] tb_gateway.gw_connect_device(tb_name) tb_gateway.gw_send_attributes(tb_name, {"discovered": False}) tb_gateway.gw_disconnect_device(tb_name) dev_data["scanned"].clear() while not known_devices_found: try: print("Scanning BLE devices...") scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(15.0) for dev in devices: print("Device {} ({}), RSSI={} dB".format( dev.addr, dev.addrType, dev.rssi)) for (adtype, desc, value) in dev.getScanData(): print(" {} = {}".format(desc, value)) if desc == "Complete Local Name" and value in known_devices: print(" [!] Known device found:", value) tb_name = value + "_" + dev.addr.replace(':', '').upper() known_devices[value]["scanned"][dev.addr] = { "inst": known_devices[value]["extension"](), "periph": Peripheral(), "tb_name": tb_name } # Force TB to create a device tb_gateway.gw_connect_device(tb_name) tb_gateway.gw_send_attributes( tb_name, { "discovered": True, "type": value, "mac_addr": dev.addr, "description": known_devices[value]["desription"] }) tb_gateway.gw_disconnect_device(tb_name) known_devices_found = True except Exception as e: print("Exception caught:", e)
DefaultDelegate.__init__(self) self.scanner = None self.timeout = 0 def handleDiscovery(self, dev, isNewDev, isNewData): if dev.addr in sensorTags: for (adtype, desc, value) in dev.getScanData(): print("new sensortag values :: %s = %s || Adtype: %s" % (desc, value, adtype)) if adtype == 255: raw_values = bytearray.fromhex(value).decode().split(',') sensor_values = { 'x': raw_values[0], 'y': raw_values[1], 'z': raw_values[2], 'id': dev.addr } print("sending to server") print(sensor_values) scanner = Scanner().withDelegate(ScanDelegate()) scanner.delegate.scanner = scanner # I know, this makes me cringe too scanner.timeout = 10 devices = scanner.scan(scanner.timeout, passive=True) # for dev in devices: # print("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)) # for (adtype, desc, value) in dev.getScanData(): # print(" %s = %s || Adtype: %s" % (desc, value, adtype))
class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): if isNewDev: print ("Discovered device", dev.addr) elif isNewData: print ("Received new data from", dev.addr) if __name__=="__main__": scanner = Scanner ().withDelegate(ScanDelegate()) devs = scanner.scan (5.0) mac = '' for dev in devs: # print ("Devices {}, ({}) RSSI {}".format (dev.addr, dev.addrType, dev.rssi)) mac = dev.addr # print (dev.__class__, mac) try: conn = Peripheral (mac, ADDR_TYPE_PUBLIC) conn.getServices () # needed to get the services property populated? except BTLEException: try: conn = Peripheral (mac, ADDR_TYPE_RANDOM) conn.getServices ()
def scan_devs(self, timeout=8, scan_type='active', sort='rssi') -> LeDevicesScanResult: """Perform LE Devices scanning and return scan reuslt as LeDevicesScanResult scan_type - 'active' or 'passive' """ if scan_type == 'adv': return scanner = Scanner(self.devid).withDelegate(LEDelegate()) #print("[Debug] timeout =", timeout) spinner = Halo(text="Scanning", spinner={'interval': 200, 'frames': ['', '.', '.'*2, '.'*3]}, placement='right') # scan() 返回的 devs 是 dictionary view。 if scan_type == 'active': # Active scan 会在 LL 发送 SCAN_REQ PDU logger.warning('Before doing an active scan, make sure you spoof your BD_ADDR.') logger.info('LE active scanning on %s with timeout %d sec\n' % \ (blue('hci%d'%self.devid), timeout)) spinner.start() devs = scanner.scan(timeout) spinner.stop() elif scan_type == 'passive': logger.info('LE passive scanning on %s with timeout %d sec\n' % \ (blue('hci%d'%self.devid), timeout)) spinner.start() devs = scanner.scan(timeout, passive=True) spinner.stop() else: logger.error('Unknown LE scan type') return if sort == 'rssi': devs = list(devs) # 将 dictionary view 转换为 list devs.sort(key=lambda d:d.rssi) for dev in devs: dev_info = LeDeviceInfo(dev.addr.upper(), dev.addrType, dev.connectable, dev.rssi) self.devs_scan_result.add_device_info(dev_info) # print('Addr: ', blue(dev.addr.upper())) # print('Addr type: ', blue(dev.addrType)) # print('Connectable:', # green('True') if dev.connectable else red('False')) # print("RSSI: %d dB" % dev.rssi) # print("General Access Profile:") for (adtype, desc, val) in dev.getScanData(): ad_struct = AdStruct(adtype, val) dev_info.add_ad_structs(ad_struct) # 打印当前 remote LE dev 透露的所有 GAP 数据(AD structure)。 # # 如果 bluepy.scan() 执行的是 active scan,那么这些 GAP 数据 # 可能同时包含 AdvData 与 ScanRspData。其中 AdvData 由 remote LE # dev 主动返回,ScanRspData 由 remote BLE dev 响应 SCAN_REQ 返回。 # # 虽然 LL 分开定义了 Advertising PDUs (ADV_IND, ADV_DIRECT_IND...) # 和 Scanning PDUs (SCAN_REQ, SCAN_RSP)。但它们分别包含的 AdvData # 与 ScanRspData 到了 HCI 层都被放在了 HCI_LE_Advertising_Report # event 中。HCI_LE_Advertising_Report 的 Event_Type 标识了这些数 # 据具体来源于哪个 LL 层的 PDU。另外 ScanRspData 与 AdvData 的格式 # 完全相同,都是 GAP 协议标准定义的 AD structure。 # # 在 LL 定义的 Advertising PDUs 中 ADV_DIRECT_IND 一定不会包含 # AdvData。其余的 ADV_IND,ADV_NONCONN_IND 以及 ADV_SCAN_IND 都 # 可能包含 AdvData。 # # 另外 getScanData() 返回的 desc 还可以通过 ScanEntry.getDescription() # 单独获取;val 还可以通过 ScanEntry.getValueText() 单独获取; # adtype 表示当前一条 GAP 数据(AD structure)的类型。 return self.devs_scan_result
def foundLDSdevices(autoconnect=False): global _ldsdevices global _ndev global _devmap global _ldevmap global _devices global _meshname global _network global DEBUG autoconenctID = -1 # Reset bluetooth adaptor _network.registerConnectableDevices(SCANDURATION) # if DEBUG: print("%s Debug: Telink devices found: %s " % (time.strftime('%F %H:%M:%S'), _network.devices)) telink_scanned_devices = _network.devices scanned = False scanner = Scanner().withDelegate(ScanDelegate()) le_scanned_devices = scanner.scan(SCANDURATION) scanned = True if not scanned: print("Fatal error: cannot scan for Bluetooth devices") sys.exit(255) time.sleep(5) count = 0 maxrssi = MINDISCRSSI scanned_devices = [] # Get intersection of the two scanned records and devmap for dev in le_scanned_devices: for (adtype, desc, value) in dev.getScanData(): if ((adtype == 9) and (value == _meshname)): for tdev in telink_scanned_devices: # print("Matching %s with %s" % (dev.addr, tdev.mac_address)) if (tdev.mac_address == dev.addr): dev.seq = count mdata = dev.getValueText(255) sige = mdata.find("0001020304050607") if sige >= 4: sigb = sige - 4 sigs = mdata[sigb:sige] + "0000" dev.deviceID = unpack('<i', unhexlify(sigs))[0] if _ldevmap > 0: for details in _devices: # if DEBUG: print("%s DEBUG: Matching ID %d of MAC %s with %s" % (time.strftime('%F %H:%M:%S'), dev.deviceID, dev.addr, toMACString(details['deviceMac']))) if isBLEMACEqual( dev.addr, toMACString(details['deviceMac'])): dev.attr = details dev.isBad = False if DEBUG: print( "%s DEBUG: %s has ID %d" % (time.strftime('%F %H:%M:%S'), dev.attr['deviceName'], dev.deviceID)) count += 1 _ldsdevices[count] = dev if dev.rssi > maxrssi: maxrssi = dev.rssi autoconenctID = dev.deviceID if DEBUG: print( "%s DEBUG: [%s] MAC:%s RSSI: %s ID:%s" % (time.strftime( '%F %H:%M:%S'), dev.seq, dev.addr, dev.rssi, dev.deviceID)) _ndev = count if _ndev > 0: try: pickle.dump(_ldsdevices, open("dbcache.p", "wb")) except: print("%s ERROR: Cannot save presistance dbcache.p" % time.strftime('%F %H:%M:%S')) if DEBUG: print( "%s DEBUG: %s devices found and saved. Will auto connect to device %s" % (time.strftime('%F %H:%M:%S'), _ndev, autoconenctID)) return int(autoconenctID)
# possible to send chat messages, not receive). # # To use, run 'pip3 install bluepy', then 'python3 test_client.py'. # NOTE: This script MUST run as root! import json import time from bluepy.btle import Scanner, Peripheral from uuid import uuid4 from gatt_constants import SERVICE_UUID, CHARACTERISTIC_UUID scanner = Scanner() while True: print('Scanning for devices...') devices = scanner.scan(10.0) for dev in devices: print(f'Device {dev.addr} (RSSI: {dev.rssi})') for (adtype, desc, value) in dev.getScanData(): print(f'Adtype: {adtype}, desc: {desc}, value: {value}') if adtype == 7 and value == SERVICE_UUID: print( ' >> Found the DistributedChat service, finding characteristics...' ) peripheral = Peripheral(dev.addr, dev.addrType, dev.iface) characteristics = peripheral.getCharacteristics( uuid=CHARACTERISTIC_UUID) if characteristics: my_name = 'Test Client' my_id = str(uuid4()) logical_clock = 0
def start(self, notify): scanner = Scanner() scanner.withDelegate(ScanDelegate(scanner, notify)) scanner.scan(10.0)
if isNewDev: pass #print ("Discovered device", dev.addr ) #print(dev) elif isNewData: pass print ("Received new data from", dev.addr) def handleNotification(self, cHandle, data): # ... perhaps check cHandle # ... process 'data' pass print("Scanning for Wallet") scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(5.0) wallet_address = 0 for dev in devices: print ("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi) ) for (adtype, desc, value) in dev.getScanData(): print (" %s = %s" % (desc, value)) if dev.rssi > -65 : print("Get Wallet address:%s!" % dev.addr) wallet_address = dev.addr if wallet_address == 0: print ("No wallet found") exit() p = Peripheral(wallet_address,btle.ADDR_TYPE_PUBLIC) print(p.setMTU(144+3)) #not actually changing MTU
#!/usr/bin/python from __future__ import print_function from time import gmtime, strftime, sleep from bluepy.btle import Scanner, DefaultDelegate, BTLEException import sys class ScanDelegate(DefaultDelegate): def handleDiscovery(self, dev, isNewDev, isNewData): print(strftime("%Y-%m-%d %H:%M:%S", gmtime()), dev.addr, dev.getScanData()) sys.stdout.flush() scanner = Scanner().withDelegate(ScanDelegate()) # listen for ADV_IND packages for 10s, then exit scanner.scan(10.0, passive=True)
#blesensor table is date, time, addr, location, temp, accero # cur = conn.cursor() dostr = 'INSERT INTO data VALUES (CURRENT_DATE(), NOW(), %s, %s, %s, %s);' #6 cur.execute (dostr, (addr, loc, temp, accero)) # conn.commit() scanner = Scanner().withDelegate(ScanDelegate()) # myConnection = pymysql.connect (host=hostname, user=username, passwd=password, db=database) ManuDataHex = [] ReadLoop = True RetryCount = 0 try: while (ReadLoop): devices = scanner.scan(2.0) ManuData = "" for dev in devices: entry = 0 AcceleroData = 0 AcceleroType = 0 TempData = 0 for saddr in SENSOR_ADDRESS: entry += 1 if (dev.addr == saddr): print (" ") print ("Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)) CurrentDevAddr = saddr CurrentDevLoc = SENSOR_LOCATION[entry-1] data['RSSI'] = dev.rssi for (adtype, desc, value) in dev.getScanData():
list_aux = list_aux[1].split('Y') datax = list_aux[0] list_aux = list_aux[1].split('Z') datay = list_aux[0] dataz = list_aux[1] return; ############################################### # Scanning Devices ############################################### os.system("sudo hciconfig hci0 down") os.system("sudo hciconfig hci0 up") print " " print "Scanning devices..." scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(8.0) ############################################### # Connecting Devices ############################################### print " " print "Connecting to nodes..." for dev in devices: # Creating Bendsaw Peripheral if dev.addr == MAC_DIC['BENDSAW']: print " " print "Device %s (%s) Bendsaw found, connecting..." %(dev.addr, dev.addrType) bndsw = Peripheral(dev.addr, dev.addrType) nodes['bendsaw'] = bndsw for (adtype, desc, value) in dev.getScanData():
keepScanning = False if __name__ == '__main__': import signal log.basicConfig(level=logging.DEBUG) log.info('OHHAI') for sig in [signal.SIGHUP, signal.SIGUSR1, signal.SIGUSR2, signal.SIGTERM, signal.SIGQUIT, signal.SIGINT]: signal.signal(sig, sighandler) bm = BeepManager() bm.thread.start() while keepScanning: try: log.info('Starting scan...') scanner = Scanner().withDelegate(ScanDelegate()) scanner.scan(30.0) except Exception as e: log.error('while scanning: %s: %s' % (type(e), e)) bm.shutdown() bm.thread.join() log.info('KTHXBYE')
def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): for (adtype, desc, value) in dev.getScanData(): if len(value) % 2 == 0: ba = bytearray(binascii.unhexlify(value)) if ba[0] == 0x4C: print('Temp sensor {0}'.format(ba[21])) major = ba[21] rh = 125 * (ba[22] * 256) / 65536 -6 temp = 175.72 * (ba[23] * 256) / 65536 - 46.85 t = time.localtime() timeStr = time.strftime("%a, %d %b %Y %H:%M:%S", t) outStr = '{0}, {1}, {2}, {3}, {4}'.format(dev.addr, timeStr, time.mktime(t), rh, temp) with open('temp_data.csv', 'a') as csvfile: csvfile.write(outStr) csvfile.write('\n') os.chdir('/home/pi/projects/ble_beacon') while True: scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(100) for dev in devices: print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi) for (adtype, desc, value) in dev.getScanData(): print " %s = %s" % (desc, value)
"device": "TokenCube 1", "addr": "dc:00:62:95:62:67", "type": "ambient" } } INFLUX_SERVER = os.environ.get("INFLUX_SERVER", None) or "raspberrypi.local" INFLUX_DATABASE = os.environ.get("INFLUX_DB", None) or "sensors" INFLUX_USER = os.environ.get("INFLUX_USER", None) or "root" INFLUX_PASSWORD = os.environ.get("INFLUX_PASSWORD", None) or "root" if __name__ == "__main__": print "Creating Scanner" delegate = DeviceForwardingDelegate() delegate.handlers.append(IGrillHandler(device_settings)) delegate.handlers.append(TokenCubeHandler(device_settings)) scanner = Scanner() scanner.withDelegate(delegate) print "Connecting to InfluxDB server" persistence = DataPersistence(INFLUX_SERVER, INFLUX_DATABASE, INFLUX_USER, INFLUX_PASSWORD) while True: print "Scanning..." scanner.scan(30) print "Persisting..." for handler in delegate.handlers: handler.persist_stats(persistence)
class BLEConnector(Connector, Thread): def __init__(self, gateway, config, connector_type): super().__init__() self.__connector_type = connector_type self.__default_services = list(range(0x1800, 0x183A)) self.statistics = {'MessagesReceived': 0, 'MessagesSent': 0} self.__gateway = gateway self.__config = config self.setName( self.__config.get( "name", 'BLE Connector ' + ''.join(choice(ascii_lowercase) for _ in range(5)))) self._connected = False self.__stopped = False self.__previous_scan_time = time.time() - 10000 self.__previous_read_time = time.time() - 10000 self.__check_interval_seconds = self.__config[ 'checkIntervalSeconds'] if self.__config.get( 'checkIntervalSeconds') is not None else 10 self.__rescan_time = self.__config[ 'rescanIntervalSeconds'] if self.__config.get( 'rescanIntervalSeconds') is not None else 10 self.__scanner = Scanner().withDelegate(ScanDelegate(self)) self.__devices_around = {} self.__available_converters = [] self.__notify_delegators = {} self.__fill_interest_devices() self.daemon = True def run(self): while True: if time.time( ) - self.__previous_scan_time >= self.__rescan_time != 0: self.__scan_ble() self.__previous_scan_time = time.time() if time.time( ) - self.__previous_read_time >= self.__check_interval_seconds: self.__get_services_and_chars() self.__previous_read_time = time.time() time.sleep(.1) if self.__stopped: log.debug('STOPPED') break def close(self): self.__stopped = True for device in self.__devices_around: try: if self.__devices_around[device].get('peripheral') is not None: self.__devices_around[device]['peripheral'].disconnect() except Exception as e: log.exception(e) raise e def get_name(self): return self.name def on_attributes_update(self, content): log.debug(content) for device in self.__devices_around: if self.__devices_around[device]['device_config'].get( 'name') == content['device']: for requests in self.__devices_around[device]['device_config'][ "attributeUpdates"]: for service in self.__devices_around[device]['services']: if requests[ 'characteristicUUID'] in self.__devices_around[ device]['services'][service]: characteristic = self.__devices_around[device][ 'services'][service][requests[ 'characteristicUUID']]['characteristic'] if 'WRITE' in characteristic.propertiesToString(): if content['data'].get( requests['attributeOnThingsBoard'] ) is not None: try: self.__check_and_reconnect(device) content_to_write = content['data'][ requests[ 'attributeOnThingsBoard']].encode( 'UTF-8') characteristic.write( content_to_write, True) except BTLEDisconnectError: self.__check_and_reconnect(device) content_to_write = content['data'][ requests[ 'attributeOnThingsBoard']].encode( 'UTF-8') characteristic.write( content_to_write, True) except Exception as e: log.exception(e) else: log.error( 'Cannot process attribute update request for device: %s with data: %s and config: %s', device, content, self.__devices_around[device] ['device_config']["attributeUpdates"]) def server_side_rpc_handler(self, content): log.debug(content) try: for device in self.__devices_around: if self.__devices_around[device]['device_config'].get( 'name') == content['device']: for requests in self.__devices_around[device][ 'device_config']["serverSideRpc"]: for service in self.__devices_around[device][ 'services']: if requests[ 'characteristicUUID'] in self.__devices_around[ device]['services'][service]: characteristic = self.__devices_around[device][ 'services'][service][ requests['characteristicUUID']][ 'characteristic'] if requests.get( 'methodProcessing' ) and requests['methodProcessing'].upper( ) in characteristic.propertiesToString(): if content['data']['method'] == requests[ 'methodRPC']: response = None if requests['methodProcessing'].upper( ) == 'WRITE': try: self.__check_and_reconnect( device) response = characteristic.write( content['data'].get( 'params', '').encode('UTF-8'), requests.get( 'withResponse', False)) except BTLEDisconnectError: self.__check_and_reconnect( device) response = characteristic.write( content['data'].get( 'params', '').encode('UTF-8'), requests.get( 'withResponse', False)) elif requests[ 'methodProcessing'].upper( ) == 'READ': try: self.__check_and_reconnect( device) response = characteristic.read( ) except BTLEDisconnectError: self.__check_and_reconnect( device) response = characteristic.read( ) elif requests[ 'methodProcessing'].upper( ) == 'NOTIFY': try: self.__check_and_reconnect( device) delegate = self.__notify_handler( self. __devices_around[device], characteristic.handle) response = delegate.data except BTLEDisconnectError: self.__check_and_reconnect( device) delegate = self.__notify_handler( self. __devices_around[device], characteristic.handle) response = delegate.data if response is not None: log.debug( 'Response from device: %s', response) if requests['withResponse']: response = 'success' self.__gateway.send_rpc_reply( content['device'], content['data']['id'], str(response)) else: log.error( 'Method for rpc request - not supported by characteristic or not found in the config.\nDevice: %s with data: %s and config: %s', device, content, self.__devices_around[device] ['device_config']["serverSideRpc"]) except Exception as e: log.exception(e) def is_connected(self): return self._connected def open(self): self.__stopped = False self.start() def device_add(self, device): for interested_device in self.__devices_around: if device.addr.upper( ) == interested_device and self.__devices_around[ interested_device].get('scanned_device') is None: self.__devices_around[interested_device][ 'scanned_device'] = device self.__devices_around[interested_device][ 'is_new_device'] = True log.debug('Device with address: %s - found.', device.addr.upper()) def __get_services_and_chars(self): for device in self.__devices_around: try: if self.__devices_around.get( device) is not None and self.__devices_around[ device].get('scanned_device') is not None: log.debug('Connecting to device: %s', device) if self.__devices_around[device].get('peripheral') is None: address_type = self.__devices_around[device][ 'device_config'].get('addrType', "public") peripheral = Peripheral( self.__devices_around[device]['scanned_device'], address_type) self.__devices_around[device][ 'peripheral'] = peripheral else: peripheral = self.__devices_around[device][ 'peripheral'] try: log.info(peripheral.getState()) except BTLEInternalError: peripheral.connect( self.__devices_around[device]['scanned_device']) try: services = peripheral.getServices() except BTLEDisconnectError: self.__check_and_reconnect(device) services = peripheral.getServices() for service in services: if self.__devices_around[device].get( 'services') is None: log.debug( 'Building device %s map, it may take a time, please wait...', device) self.__devices_around[device]['services'] = {} service_uuid = str(service.uuid).upper() if self.__devices_around[device]['services'].get( service_uuid) is None: self.__devices_around[device]['services'][ service_uuid] = {} try: characteristics = service.getCharacteristics() except BTLEDisconnectError: self.__check_and_reconnect(device) characteristics = service.getCharacteristics() if self.__config.get('buildDevicesMap', False): for characteristic in characteristics: descriptors = [] self.__check_and_reconnect(device) try: descriptors = characteristic.getDescriptors( ) except BTLEDisconnectError: self.__check_and_reconnect(device) descriptors = characteristic.getDescriptors( ) except BTLEGattError as e: log.debug(e) except Exception as e: log.exception(e) characteristic_uuid = str( characteristic.uuid).upper() if self.__devices_around[device][ 'services'][service_uuid].get( characteristic_uuid) is None: self.__check_and_reconnect(device) self.__devices_around[device][ 'services'][service_uuid][ characteristic_uuid] = { 'characteristic': characteristic, 'handle': characteristic.handle, 'descriptors': {} } for descriptor in descriptors: log.debug(descriptor.handle) log.debug(str(descriptor.uuid)) log.debug(str(descriptor)) self.__devices_around[device][ 'services'][service_uuid][ characteristic_uuid][ 'descriptors'][ descriptor. handle] = descriptor else: for characteristic in characteristics: characteristic_uuid = str( characteristic.uuid).upper() self.__devices_around[device]['services'][ service_uuid][characteristic_uuid] = { 'characteristic': characteristic, 'handle': characteristic.handle } if self.__devices_around[device]['is_new_device']: log.debug('New device %s - processing.', device) self.__devices_around[device]['is_new_device'] = False self.__new_device_processing(device) for interest_char in self.__devices_around[device][ 'interest_uuid']: for section in self.__devices_around[device][ 'interest_uuid'][interest_char]: data = self.__service_processing( device, section['section_config']) converter = section['converter'] converted_data = converter.convert(section, data) self.statistics[ 'MessagesReceived'] = self.statistics[ 'MessagesReceived'] + 1 log.debug(data) log.debug(converted_data) self.__gateway.send_to_storage( self.get_name(), converted_data) self.statistics['MessagesSent'] = self.statistics[ 'MessagesSent'] + 1 except BTLEDisconnectError: log.debug('Connection lost. Device %s', device) continue except Exception as e: log.exception(e) def __new_device_processing(self, device): default_services_on_device = [ service for service in self.__devices_around[device]['services'].keys() if int(service.split('-')[0], 16) in self.__default_services ] log.debug('Default services found on device %s :%s', device, default_services_on_device) converter = BytesBLEUplinkConverter( self.__devices_around[device]['device_config']) converted_data = None for service in default_services_on_device: characteristics = [ char for char in self.__devices_around[device]['services'] [service].keys() if self.__devices_around[device]['services'] [service][char]['characteristic'].supportsRead() ] for char in characteristics: read_config = { 'characteristicUUID': char, 'method': 'READ', } try: self.__check_and_reconnect(device) data = self.__service_processing(device, read_config) attribute = capitaliseName(UUID(char).getCommonName()) read_config['key'] = attribute read_config['byteFrom'] = 0 read_config['byteTo'] = -1 converter_config = [{ "type": "attributes", "clean": False, "section_config": read_config }] for interest_information in converter_config: try: converted_data = converter.convert( interest_information, data) self.statistics[ 'MessagesReceived'] = self.statistics[ 'MessagesReceived'] + 1 log.debug(converted_data) except Exception as e: log.debug(e) except Exception as e: log.debug('Cannot process %s', e) continue if converted_data is not None: # self.__gateway.add_device(converted_data["deviceName"], {"connector": self}) self.__gateway.send_to_storage(self.get_name(), converted_data) self.statistics[ 'MessagesSent'] = self.statistics['MessagesSent'] + 1 def __check_and_reconnect(self, device): # pylint: disable=protected-access while self.__devices_around[device]['peripheral']._helper is None: log.debug("Connecting to %s...", device) self.__devices_around[device]['peripheral'].connect( self.__devices_around[device]['scanned_device']) def __notify_handler(self, device, notify_handle, delegate=None): class NotifyDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) self.device = device self.data = {} def handleNotification(self, handle, data): self.data = data log.debug( 'Notification received from device %s handle: %i, data: %s', self.device, handle, data) if delegate is None: delegate = NotifyDelegate() device['peripheral'].withDelegate(delegate) device['peripheral'].writeCharacteristic(notify_handle, b'\x01\x00', True) if device['peripheral'].waitForNotifications(1): log.debug("Data received: %s", delegate.data) return delegate def __service_processing(self, device, characteristic_processing_conf): for service in self.__devices_around[device]['services']: characteristic_uuid_from_config = characteristic_processing_conf.get( 'characteristicUUID') if characteristic_uuid_from_config is None: log.error('Characteristic not found in config: %s', pformat(characteristic_processing_conf)) return None if self.__devices_around[device]['services'][service].get( characteristic_uuid_from_config) is None: continue characteristic = self.__devices_around[device]['services'][ service][characteristic_uuid_from_config]['characteristic'] self.__check_and_reconnect(device) data = None if characteristic_processing_conf.get( 'method', '_').upper().split()[0] == "READ": if characteristic.supportsRead(): self.__check_and_reconnect(device) data = characteristic.read() log.debug(data) else: log.error( 'This characteristic doesn\'t support "READ" method.') if characteristic_processing_conf.get( 'method', '_').upper().split()[0] == "NOTIFY": self.__check_and_reconnect(device) descriptor = characteristic.getDescriptors(forUUID=0x2902)[0] handle = descriptor.handle if self.__notify_delegators.get(device) is None: self.__notify_delegators[device] = {} if self.__notify_delegators[device].get(handle) is None: self.__notify_delegators[device][handle] = { 'function': self.__notify_handler, 'args': (self.__devices_around[device], handle, self.__notify_delegators[device].get(handle)), 'delegate': None } self.__notify_delegators[device][handle][ 'delegate'] = self.__notify_delegators[device][handle][ 'function'](*self.__notify_delegators[device] [handle]['args']) data = self.__notify_delegators[device][handle][ 'delegate'].data else: self.__notify_delegators[device][handle]['args'] = ( self.__devices_around[device], handle, self.__notify_delegators[device][handle]['delegate']) self.__notify_delegators[device][handle][ 'delegate'] = self.__notify_delegators[device][handle][ 'function'](*self.__notify_delegators[device] [handle]['args']) data = self.__notify_delegators[device][handle][ 'delegate'].data if data is None: log.error('Cannot process characteristic: %s with config:\n%s', str(characteristic.uuid).upper(), pformat(characteristic_processing_conf)) else: log.debug('data: %s', data) return data def __scan_ble(self): log.debug("Scanning for devices...") try: self.__scanner.scan(self.__config.get('scanTimeSeconds', 5), passive=self.__config.get( 'passiveScanMode', False)) except BTLEManagementError as e: log.error('BLE working only with root user.') log.error( 'Or you can try this command:\nsudo setcap ' '\'cap_net_raw,cap_net_admin+eip\' %s' '\n====== Attention! ====== ' '\nCommand above - provided access to ble devices to any user.' '\n========================', str(bluepy_path[0] + '/bluepy-helper')) self._connected = False raise e except Exception as e: log.exception(e) time.sleep(10) def __fill_interest_devices(self): if self.__config.get('devices') is None: log.error( 'Devices not found in configuration file. BLE Connector stopped.' ) self._connected = False return None for interest_device in self.__config.get('devices'): keys_in_config = ['attributes', 'telemetry'] if interest_device.get('MACAddress') is not None: default_converter = BytesBLEUplinkConverter(interest_device) interest_uuid = {} for key_type in keys_in_config: for type_section in interest_device.get(key_type): if type_section.get("characteristicUUID") is not None: converter = None if type_section.get('converter') is not None: try: module = TBUtility.check_and_import( self.__connector_type, type_section['converter']) if module is not None: log.debug( 'Custom converter for device %s - found!', interest_device['MACAddress']) converter = module(interest_device) else: log.error( "\n\nCannot find extension module for device %s .\nPlease check your configuration.\n", interest_device['MACAddress']) except Exception as e: log.exception(e) else: converter = default_converter if converter is not None: if interest_uuid.get( type_section["characteristicUUID"]. upper()) is None: interest_uuid[type_section[ "characteristicUUID"].upper()] = [{ 'section_config': type_section, 'type': key_type, 'converter': converter }] else: interest_uuid[type_section[ "characteristicUUID"].upper()].append({ 'section_config': type_section, 'type': key_type, 'converter': converter }) else: log.error( "No characteristicUUID found in configuration section for %s:\n%s\n", key_type, pformat(type_section)) if self.__devices_around.get( interest_device['MACAddress'].upper()) is None: self.__devices_around[ interest_device['MACAddress'].upper()] = {} self.__devices_around[interest_device['MACAddress'].upper( )]['device_config'] = interest_device self.__devices_around[interest_device['MACAddress'].upper( )]['interest_uuid'] = interest_uuid else: log.error( "Device address not found, please check your settings.")
class SmartGadgetService(Service): def __init__(self, cls, interface=None): """Base class for a Smart Gadget :class:`~msl.network.service.Service`. Parameters ---------- cls A :class:`~smartgadget.sht3x.SHT3XService` or a :class:`~smartgadget.shtc1.SHTC1Service` class type. interface : :class:`int`, optional The Bluetooth interface to use for the connection. For example, 0 or :data:`None` means ``/dev/hci0``, 1 means ``/dev/hci1``. """ super(SmartGadgetService, self).__init__(name=cls.DEVICE_NAME) self._device_name = cls.DEVICE_NAME self._cls = cls self._interface = interface self._max_attempts = 5 self._retries_remaining = 0 self._scanner = Scanner() self._gadgets_available = {} self._gadgets_connected = {} # only add a MAC address in here if the connection request was made explicitly self._requested_connections = set() def max_attempts(self) -> int: """Returns the maximum number of times to try to connect or read/write data from/to a Smart Gadget. Returns ------- :class:`int` The maximum number of times to retry. """ return self._max_attempts def set_max_attempts(self, max_attempts): """Set the maximum number of times to try to connect or read/write data from/to a Smart Gadget. Since a Bluetooth connection can drop unexpectedly, this provides the opportunity to automatically re-connect or re-send a request to a Smart Gadget. Parameters ---------- max_attempts : :class:`int` The maximum number of times to try to connect or read/write data from/to a Smart Gadget. Increasing the number of attempts will decrease the occurrence of getting a ``BTLEDisconnectError`` or a :exc:`BrokenPipeError` when sending requests, but may make sending a request take a long time while the connection automatically tries to be re-established. """ self._max_attempts = max(1, int(max_attempts)) logger.debug('The maximum number attempts has been set to {}'.format( self._max_attempts)) def scan(self, timeout=10, passive=False) -> List[str]: """Scan for Smart Gadgets that are within Bluetooth range. Parameters ---------- timeout : :class:`float`, optional The number of seconds to scan for Smart Gadgets. passive : :class:`bool`, optional Use active (to obtain more information when connecting) or passive scanning. Returns ------- :class:`list` of :class:`str` A list of MAC addresses of the Smart Gadgets that are available for this particular SHTxx class. """ self._gadgets_available.clear() logger.info('Scanning for {!r}...'.format(self._device_name)) for d in self._scanner.scan(timeout=timeout, passive=passive): if d.getValueText(d.COMPLETE_LOCAL_NAME) == self._device_name: self._gadgets_available[d.addr] = d logger.info('Found {} Smart Gadgets'.format( len(self._gadgets_available))) return list(self._gadgets_available) def connect_gadget(self, mac_address, strict=True) -> bool: """Connect to the specified Smart Gadget. It is not necessary to call this method to connect to a Smart Gadget via Bluetooth before fetching data from it. The Bluetooth connection will automatically be created and destroyed when requesting information from the Smart Gadget if the Bluetooth connection does not already exist. Establishing a Bluetooth connection to a Smart Gadget takes approximately 7 seconds. If you are only requesting data from a couple of Smart Gadgets then connecting to each Smart Gadget at the beginning of your script and then fetching data in a loop would be more efficient if you want to fetch data as quickly as possible. However, there are hardware limits to how many Smart Gadgets can simultaneously have a Bluetooth connection with the Raspberry Pi. So, there is a compromise between how quickly your program can fetch data and how many Smart Gadgets you want to fetch data from. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget to connect to. strict : :class:`bool`, optional Whether to raise an error if the Smart Gadget could not be connected to. Returns ------- :class:`bool` Whether the connection was successful. """ failed = self.connect_gadgets([mac_address], strict=strict)[1] return len(failed) == 0 def connect_gadgets(self, mac_addresses, strict=True) -> Tuple[list, list]: """Connect to the specified Smart Gadgets. See :meth:`.connect_gadget` for more details. Parameters ---------- mac_addresses : :class:`list` of :class:`str` A list of MAC addresses of the Smart Gadgets to connect to. strict : :class:`bool`, optional Whether to raise an error if a Smart Gadget could not be connected to. Returns ------- :class:`tuple` of :class:`list` A list of MAC addresses of the Smart Gadgets that were successfully connected to and the MAC addresses of the Smart Gadgets that could not be connected to. """ failed_connections = [] for mac_address in mac_addresses: self._retries_remaining = self._max_attempts try: self._connect(mac_address) self._requested_connections.add(mac_address) except BTLEDisconnectError as e: if strict: logger.error(e) raise else: logger.warning( 'Could not connect to {!r}'.format(mac_address)) failed_connections.append(mac_address) return list(self._gadgets_connected), failed_connections def connected_gadgets(self) -> List[str]: """Returns the MAC addresses of the Smart Gadgets that are currently connected. Returns ------- :class:`list` of :class:`str` The MAC addresses of the currently-connected Smart Gadgets. """ return list(self._gadgets_connected) def disconnect_gadget(self, mac_address): """Disconnect the Smart Gadget with the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget to disconnect from. """ gadget = self._gadgets_connected.pop(mac_address, None) if gadget: try: logger.info('Disconnecting from {!r}...'.format(mac_address)) gadget.disconnect() except: pass try: self._requested_connections.remove(mac_address) except: pass def disconnect_gadgets(self): """Disconnect from all Smart Gadgets.""" for mac_address, gadget in self._gadgets_connected.items(): try: gadget.disconnect() except: pass try: self._requested_connections.remove(mac_address) except: pass self._gadgets_connected.clear() logger.info('Disconnected from all Smart Gadgets') def temperature(self, mac_address) -> float: """Returns the current temperature for the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`float` The temperature [degree C]. """ return self._process('temperature', mac_address) def humidity(self, mac_address) -> float: """Returns the current humidity for the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`float` The humidity [%RH]. """ return self._process('humidity', mac_address) def dewpoint(self, mac_address, temperature=None, humidity=None) -> float: """Returns the dew point for the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. temperature : :class:`float`, optional The temperature [degree C]. If :data:`None` then reads the current temperature value from the Smart Gadget. humidity : :class:`float`, optional The humidity [%RH]. If :data:`None` then reads the current humidity value from the Smart Gadget. Returns ------- :class:`float` The dew point [degree C]. """ return self._process('dewpoint', mac_address, temperature=temperature, humidity=humidity) def temperature_humidity(self, mac_address) -> Tuple[float, float]: """Returns the current temperature and humidity for the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`float` The temperature [degree C]. :class:`float` The humidity [%RH]. """ return self._process('temperature_humidity', mac_address) def temperature_humidity_dewpoint( self, mac_address) -> Tuple[float, float, float]: """Returns the current temperature, humidity and dew point for the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`float` The temperature [degree C]. :class:`float` The humidity [%RH]. :class:`float` The dew point [degree C]. """ return self._process('temperature_humidity_dewpoint', mac_address) def battery(self, mac_address) -> int: """Returns the battery level for the specified MAC address. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`int` The battery level [%]. """ return self._process('battery', mac_address) def rssi(self, mac_address) -> int: """Returns the Received Signal Strength Indication (RSSI) for the last received broadcast from the device. This is an integer value measured in dB, where 0 dB is the maximum (theoretical) signal strength, and more negative numbers indicate a weaker signal. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`int` or :data:`None` The RSSI value if the :class:`~smartgadget.smart_gadget.SmartGadget` was initialized with a :ref:`ScanEntry <scanentry>` object. Otherwise returns :data:`None`. """ return self._process('rssi', mac_address) def info(self, mac_address) -> dict: """Returns all available information from the Smart Gadget. Parameters ---------- mac_address : :class:`str` The MAC address of the Smart Gadget. Returns ------- :class:`dict` Includes information such as the firmware, hardware and software version numbers, the battery level, the temperature, humidity and dew point values and the timing information about the data logger (if the Smart Gadgets supports logging). """ return self._process('info', mac_address) def shutdown_service(self): """Shutdown the Smart Gadget :class:`~msl.network.service.Service` and the Network :class:`~msl.network.manager.Manager`.""" self.disconnect_gadgets() def restart_bluetooth(self): """Restart the Bluetooth driver on the Raspberry Pi. This can fix scanning issues or connection timeouts. .. attention:: Calling this method will disconnect all Smart Gadgets that are currently connected to the Raspberry Pi. """ logger.debug('Restarting bluetooth...') self.disconnect_gadgets() subprocess.run(['sudo', 'systemctl', 'restart', 'bluetooth'], check=True) @staticmethod def rpi_date() -> str: """Returns the current date of the Raspberry Pi. Returns ------- :class:`str` The current date of the Raspberry Pi in the ISO-8601 format. """ return datetime.now().isoformat(sep=' ') @staticmethod def set_rpi_date(date): """Set the date of the Raspberry Pi. This is useful if the Raspberry Pi does not have internet access on startup to sync with an online NTP server. Does not set the time zone. Parameters ---------- date Can be a :class:`~datetime.datetime` object, an ISO-8601 formatted :class:`str`, a :class:`float` in seconds, or an :class:`int` in milliseconds. """ date = milliseconds_to_datetime(timestamp_to_milliseconds(date)) logger.debug("Setting Raspberry Pi date to '{}'".format(date)) subprocess.run( ['sudo', 'date', '-s', date.strftime('%a %d %b %Y %I:%M:%S %p')], check=True) def _connect(self, mac_address): """Connect to a Smart Gadget.""" gadget = self._gadgets_connected.get(mac_address) if gadget is None: device = self._gadgets_available.get(mac_address) or mac_address while gadget is None: try: self._retries_remaining -= 1 if mac_address in self._requested_connections: logger.info( 'Re-connecting to {!r}...'.format(mac_address)) else: logger.info( 'Connecting to {!r}...'.format(mac_address)) gadget = self._cls(device, interface=self._interface) self._gadgets_connected[mac_address] = gadget except BTLEDisconnectError as e: if self._retries_remaining < 1: logger.error(e) raise text = 'retry remains' if self._retries_remaining == 1 else 'retries remaining' logger.warning('{} -- {} {}'.format( e, self._retries_remaining, text)) return gadget def _process(self, method_name, mac_address, **kwargs): """All Smart Gadget services call this method to process the request.""" self._retries_remaining = self._max_attempts while True: gadget = self._connect(mac_address) try: logger.info('Processing {!r} from {!r} -- kwargs={}'.format( method_name, mac_address, kwargs)) out = getattr(gadget, method_name)(**kwargs) if mac_address not in self._requested_connections: self.disconnect_gadget(mac_address) return out except (BrokenPipeError, BTLEDisconnectError) as e: if self._retries_remaining < 1: logger.error(e) raise self._gadgets_connected.pop(mac_address, None) text = 'retry remains' if self._retries_remaining == 1 else 'retries remaining' logger.warning('{} -- {} {}'.format(e, self._retries_remaining, text))
def connect(pi): from bluepy.btle import Scanner, DefaultDelegate, Peripheral, ADDR_TYPE_RANDOM, UUID, BTLEException device = None addr = None _LOGGER.debug("Starting plejd connection") disconnect(pi) scanner = Scanner() for i in range(1, 10): devs = sorted(list(scanner.scan(1)), key=lambda d: d.rssi)[::-1] for d in devs: for (adtype, desc, value) in d.getScanData(): if (adtype == 8 and value == "P mesh"): try: dev = Peripheral(d, addrType=ADDR_TYPE_RANDOM) if dev.getServiceByUUID(UUID(PLEJD_SERVICE)): device = dev else: dev.disconnect() break except BTLEException as e: _LOGGER.warning( "failed connecting to device '%s' : '%s'" % (d.addr, e)) if device: break if device is None: _LOGGER.warning("no device found on iteration %d" % (i)) else: break if device == None: _LOGGER.warning("Failed to find a Plejd device to connect to") return _LOGGER.debug("Connected to Plejd device '%s'" % (device.addr)) pi["device"] = device pi["address"] = binascii.a2b_hex(device.addr.replace(':', ''))[::-1] pi["handles"] = {} pi["handles"]["last_data"] = pi["device"].getCharacteristics( uuid=UUID(LAST_DATA_UUID))[0].getHandle() pi["handles"]["auth"] = pi["device"].getCharacteristics( uuid=UUID(AUTH_UUID))[0].getHandle() pi["handles"]["ping"] = pi["device"].getCharacteristics( uuid=UUID(PING_UUID))[0].getHandle() pi["handles"]["data"] = pi["device"].getCharacteristics( uuid=UUID(DATA_UUID))[0].getHandle() class PlejdDelegate(DefaultDelegate): def handleNotification(self, handle, value): if handle == pi["handles"]["last_data"]: dec = plejd_enc_dec(pi["key"], pi["address"], value) # check if this is a device we care about if dec[0] in PLEJD_DEVICES: device = PLEJD_DEVICES[dec[0]] else: _LOGGER.debug("no match for device '%d' (%s)" % (dec[0], binascii.b2a_hex(dec))) return dim = 0xffff state = None if dec[3:5] == b'\x00\xc8' or dec[3:5] == b'\x00\x98': # 00c8 and 0098 both mean state+dim state = dec[5] dim = int.from_bytes(dec[6:8], 'little') elif dec[3:5] == b'\x00\x97': # 0097 is state only state = dec[5] else: _LOGGER.debug("no match for command '%s' (%s)" % (binascii.b2a_hex(dec[3:5], dec))) return if (state == 0): state = False else: state = True device.update_state(state, dim) class PlejdNotificationThread(Thread): def __init__(self): Thread.__init__(self) self.stopped = True _LOGGER.debug("setting up notification thread") def stop(self): _LOGGER.debug("stopping notification thread") self.stopped = True import time def run(self): from bluepy.btle import BTLEInternalError _LOGGER.debug("starting notification thread") self.stopped = False while True: try: pi["device"].waitForNotifications(1) except BTLEInternalError as e: _LOGGER.warning("Encountered bluepy internal error: '%s'" % (e)) if self.stopped: break _LOGGER.debug("exiting notification thread") authenticate(pi) # the notification handle is last_data + 2 pi["device"].writeCharacteristic(pi["handles"]["last_data"] + 2, b'\x02\x00') pi["device"].withDelegate(PlejdDelegate()) pi["thread"] = PlejdNotificationThread() pi["thread"].start() _LOGGER.debug("all plejd setup completed")
print(scanentry.getScanData()) print(scanentry.getValueText(9)) print(scanentry.getValueText(22)) #scanner = Scanner().withDelegate(BTThermometerDelegate("C4:B3:61:94:78:38")) #while True: #devices = scanner.scan() from bluepy.btle import Scanner, DefaultDelegate class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): if isNewDev: print "Discovered device", dev.addr elif isNewData: print "Received new data from", dev.addr scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(10.0) for dev in devices: print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi) for (adtype, desc, value) in dev.getScanData(): print " %s = %s" % (desc, value)
class BLEScan(): bledev = 0 timeout = 5.0 scanner = None devices = [] devrssi = [] lastscan = 0 def __init__(self,devnum=0,timeout=5.0): self.bledev = int(devnum) self.timeout = float(timeout) self.scanner = None self.devices = [] self.devrssi = [] self.lastscan = 0 self._scanning = False self.scantime = 10 self.minsleep = 15 self.maxsleep = 40 def stop(self): try: if self.scanner is not None: self.scanner.stop() except: pass self._scanning = False def scan(self): result = False devices = [] self._scanning = True try: self.scanner = Scanner(self.bledev) devices = self.scanner.scan(self.timeout) result = True self.lastscan = time.time() except Exception as e: print("BLE error: ",e) self.devices = [] self.devrssi = [] self._scanning = False tempdev = [] temprssi = [] for dev in devices: try: if self.bledev == int(dev.iface): temprssi.append(dev.rssi) tempdev.append(str(dev.addr).lower().strip()) except: pass self.devices = tempdev self.devrrsi = temprssi return result def isdevonline(self,devaddress): return (self.getdevrssi(devaddress) != -100) def getdevrssi(self,devaddress): try: for d in range(len(self.devices)): if str(devaddress).lower().strip()==str(self.devices[d]).lower().strip(): return self.devrrsi[d] return -100 except Exception as e: return -100 def getage(self): if self.lastscan==0: return -1 try: result = time.time()-self.lastscan except: result = -1 return result def sniff(self, callback,startwait=0,scantime=10,minsleep=15,maxsleep=40): self._scanning = True self.scantime = scantime self.minsleep = minsleep self.maxsleep = maxsleep _blestatus = BLEHelper.BLEStatus[self.bledev] time.sleep(startwait) try: if self.timeout==0: while self._scanning: while _blestatus.norequesters()==False or _blestatus.nodataflows()==False or _blestatus.isscaninprogress(): time.sleep(0.5) # print("scan start")#debug _blestatus.reportscan(1) try: self.scanner = Scanner(self.bledev).withDelegate(SniffDelegate(callback)) except: pass self.scanner.clear() self.scanner.start(passive=True) self.scanner.process(scantime) self.scanner.stop() _blestatus.reportscan(0) # print("scan pause")#debug time.sleep(uniform(minsleep,maxsleep)) else: while _blestatus.norequesters()==False or _blestatus.nodataflows()==False or _blestatus.isscaninprogress(): time.sleep(0.5) _blestatus.reportscan(1) self.scanner = Scanner(self.bledev).withDelegate(SniffDelegate(callback)) self.scanner.scan(self.timeout,passive=True) _blestatus.reportscan(0) self.lastscan = time.time() except Exception as e: _blestatus.reportscan(0) self._scanning = False
#-*- coding: utf-8 -*- from bluepy.btle import Scanner, DefaultDelegate from SigObject import sigObject from log import logger import signals class ScanDelegate(DefaultDelegate): def __init__(self): DefaultDelegate.__init__(self) def handleDiscovery(self, dev, isNewDev, isNewData): #logger.debug("%s[%d]" % (dev.addr, dev.rssi)) sigObject.emit(signals.BLE_INFO_UPDATE, dev.addr, dev.rssi) if __name__ == "__main__": from bluepy.btle import Scanner scanner = Scanner().withDelegate(ScanDelegate()) scanner.scan(4)
############################################### def split_accel_data(data): global datax, datay, dataz list_aux = data.split('X') list_aux = list_aux[1].split('Y') datax = list_aux[0] list_aux = list_aux[1].split('Z') datay = list_aux[0] dataz = list_aux[1] return; ############################################### # Scanning Devices ############################################### scanner = Scanner().withDelegate(ScanDelegate()) devices = scanner.scan(6.0) ############################################### # Connecting Devices ############################################### print " " print "Connecting to nodes..." print " " for dev in devices: if dev.addr == BNDSW_MAC_ADDR: print "Device %s (%s) Bendsaw found, connecting..." %(dev.addr, dev.addrType) bndsw = Peripheral(dev.addr, dev.addrType) for (adtype, desc, value) in dev.getScanData(): print " %s = %s" % (desc, value) print " " if dev.addr == SPIRO_MAC_ADDR: