Giter VIP home page Giter VIP logo

adafruit_circuitpython_ble's Introduction

Introduction

Documentation Status

Discord

Build Status

Code Style: Black

This module provides higher-level BLE (Bluetooth Low Energy) functionality, building on the native _bleio module.

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle.

Installing from PyPI

Warning: Linux support is very limited. See Adafruit Blinka _bleio for details.

On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally from PyPI. To install for current user:

pip3 install adafruit-circuitpython-ble

To install system-wide (this may be required in some cases):

sudo pip3 install adafruit-circuitpython-ble

To install in a virtual environment in your current project:

mkdir project-name && cd project-name
python3 -m venv .venv
source .venv/bin/activate
pip3 install adafruit-circuitpython-ble

Usage Example

from adafruit_ble import BLERadio

radio = BLERadio()
print("scanning")
found = set()
for entry in radio.start_scan(timeout=60, minimum_rssi=-80):
    addr = entry.address
    if addr not in found:
        print(entry)
    found.add(addr)

print("scan done")

Documentation

API documentation for this library can be found on Read the Docs.

For information on building library documentation, please check out this guide.

Contributing

Contributions are welcome! Please read our Code of Conduct before contributing to help this project stay welcoming.

adafruit_circuitpython_ble's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adafruit_circuitpython_ble's Issues

More thorough documentation

The library could really use more thorough documentation, through more examples, overview text, a, detailed explanatory text. A Learn Guide is probably appropriate, but there should be more inline documentation too. The declarative nature of Service and Advertisement needs to be more thoroughly explained, for example.

BLEConnection object can not find my defined Service

Hello,
So I am trying to use my husarion Rosbot to connect and receive file data from the nrf52 bluefruit BLE microprocessor. So the bluefruit already has defined Services and is advertising these services. This service has already been given permission to accept read and writing from the central. So, the thing is that I can connect to the bluefruit from the linux central device just fine, and even print out the defined 128-bit UUID onto the terminal showing that the central device can see all services being advertised but when I go to access the defined service and then want to write to it I get the error:
raise KeyError("{!r} object has no service {}".format(self, key)) KeyError: "<adafruit_ble.BLEConnection object at <0x.....> object has no service <class '__main__.scanParametersSvc'>"

The scanParametersSvc is the one I defined. I defined this service as a class, similar to how nordic.py defines its UARTService class.

`from adafruit_ble.services.standard import Service
from adafruit_ble.uuid import VendorUUID
from adafruit_ble.characteristics.stream import StreamOut, StreamIn

class ScanParametersSvc(Service):
uuid = VendorUUID("00001813-0000-1000-8000-00805f9b34fb")
_server_tx = StreamOut(
uuid = VendorUUID("00001813-0000-1000-8000-00805f9b34fb"),
timeout = 1.0,
buffer_size = 12, #can be changed later on
)

_server_rx = StreamIn(
	uuid = VendorUUID("00001813-0000-1000-8000-00805f9b34fb"),
	timeout = 1.0,
	buffer_size = 12,
)

def __init__(self, service=None):
    	super().__init__(service=service)
   		self.connectable = True
    	if not service:
        		self._rx = self._server_rx
        		self._tx = self._server_tx
    	else:
        		# If we're a client then swap the characteristics we use.
        		self._tx = self._server_rx
        		self._rx = self._server_tx

def read(self, nbytes=None):
    	"""
    	Read characters. If ``nbytes`` is specified then read at most that many 		bytes.
    	Otherwise, read everything that arrives until the connection times out.
    	Providing the number of bytes expected is highly recommended because it 		will be faster.
    	:return: Data read
   		:rtype: bytes or None
    	"""
    	return self._rx.read(nbytes)

def readinto(self, buf, nbytes=None):
    	"""
    	Read bytes into the ``buf``. If ``nbytes`` is specified then read at most
    	that many bytes. Otherwise, read at most ``len(buf)`` bytes.
    	:return: number of bytes read and stored into ``buf``
    	:rtype: int or None (on a non-blocking error)
    	"""
    	return self._rx.readinto(buf, nbytes)

def readline(self):
	"""
	Read a line, ending in a newline character.
	:return: the line read
	:rtype: bytes or None	
	"""
	return self._rx.readline()

@property
def in_waiting(self):
	"""The number of bytes in the input buffer, available to be read."""
	return self._rx.in_waiting

def reset_input_buffer(self):
	"""Discard any unread characters in the input buffer."""
	self._rx.reset_input_buffer()

def write(self, buf):
	"""Write a buffer of bytes."""
	self._tx.write(buf)

`

I know that that the VendorUUID is correct because I printed out the advertisement of the bluefruit and found this UUID there
Address(string="d8:7b:75:6f:a9:97") SOIL_SENSE <ProvideServicesAdvertisement complete_name=SOIL_SENSE flags=<AdvertisingFlags general_discovery le_only> Services=<BoundServiceList: 00001813-0000-1000-8000-00805f9b34fb>tx_power = 0>

The line in main that causes this error is:
scan_parameters_svc = soil_sense_connection[ScanParametersSvc]

I find this error confusing because I am able to get the device information easily, and this is once again another type of Service that the bluefruit offers. So my question is why is it able to read or access one service but not another.

I tried also to change the connection from bleak to hcitools since I am running a linux central by using
ble._adapter.ble_backend = 'hcitools
and then running the python3.8 file as sudo.

Thank you

Can't use multiprocessing on the BLE connections to retrieve data from multipe devices at the same time

I have been trying to get data out from multiple pulse-oximeters at the same time. I was able to run them separately in two different environments and able to extract data from two pulse-oximeters at the same time. I tried to use multiprocessing after the BLE connection to retrieve data parallelly from two pulse-oximeters in the same environment, the connection is getting lost and data is no longer getting received. Then I removed multiprocessing to check whether the code is right and verified that the data is getting retrieved from the code.
How do I retrieve data from multiple BLE devices at the same time using multiprocessing with the library?

Advertisements aren't including name

The various advertisement classes, including ProvideServicesAdvertisement, etc. are not including a name in the advertising packet or scan response. This means that when the devices first appear in a list, say, to connect or pair to, just the address is listed. Once the peer caches the name, it will it will show up in lists, but the name should be included in the advertisement and/or scan response.

@tannewt: in https://circuitpython.readthedocs.io/en/latest/shared-bindings/_bleio/Adapter.html#_bleio.Adapter.name, it says:

name: name of the BLE adapter used once connected. Not used in advertisements. The name is “CIRCUITPY” + the last four hex digits of adapter.address, to make it easy to distinguish multiple CircuitPython boards.

I think you added the "Not used in advertisements". Normally I would expect this name would be used as the default advertisement name.

Release 7.20 is not compatible with CircuitPython 5.3.x

While trying to advertise something using start_advertising() I constantly ran into an error:

...
File "adafruit_ble/init.py", line 191, in start_advertising
TypeError: extra keyword arguments given

After comparing the documentation of CircuitPython 5.3.x and the current version (6.x.x) regarding the underlying call to start_advertisingof Adapter 5.3.x / 6.x.x
I realized that Release 7.2.0 of this library introduced an incompatibility with CircuitPython 5.3.x:

self._adapter.start_advertising(
advertisement_bytes,
scan_response=scan_response_bytes,
connectable=advertisement.connectable,
interval=interval,
timeout=0 if timeout is None else timeout,

Which has too many parameters for CircuitPython 5.3.x

Unfortunately I'm new to (Circuit)Python so I don't know if it would be possible to have a library that is compatible with both versions of CircuitPython.
I also unterstand that (for now) I have to use Version 7.1.0 to be compatible with CircuitPython 5.3.1

VoiceOver Modifier keys not recognised by iOS device over BLE HID

When sending keystrokes to an iOS device using the new BLE HID support, any modifiers seem to be discarded. For example, using the following code after a connection has been established (where kbd is an instance of adafruit_hid.keyboard.Keyboard):

kbd.send(Keycode.CONTROL, Keycode.OPTION, Keycode.H)

With iOS VoiceOver turned on, Ctrl+Option+H should activate the Home button, showing the home screen. But VoiceOver is only reporting that the H key has been received.

On Android, I turned on the TalkBack screen reader, and then did:

kbd.send(Keycode.CONTROL, Keycode.ALT, Keycode.H)

This is likewise intended as a keystroke to activate the Home button, and on Android it worked as expected. Does iOS require keyboard reports to be constructed in a nonstandard format?

CC @dhalbert and @sinabahram

uuid has no attribute pack_into

I'm trying this out for the first time on a rpi zero w, and after installing the library I keep getting an error:

AttributeError: 'UUID' object has no attribute 'pack_into'

Running with Python 3 here is a sample of my code:

import adafruit_ble
from adafruit_ble.advertising import standard
import adafruit_ble_apple_notification_center as ancs

radio = adafruit_ble.BLERadio()
a = standard.SolicitServicesAdvertisement()
a.solicited_services.append(ancs.AppleNotificationCenterService)

Looking more closely the error is in line 63 of uuid/init.py:

def pack_into(self, buffer, offset=0):
        """Packs the UUID into the buffer at the given offset."""
        self.bleio_uuid.pack_into(buffer, offset=offset) #<-- this is where the error is coming from

any advice?

Edit: Seems like the issue is actually coming from declaring the advertisement with SolicitServicesAdvertisement() because the advertisement is a Nonetype and the radio advertising fails.

Traceback (most recent call last):
  File "ancs.py", line 16, in <module>
    radio.start_advertising(a)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_ble/__init__.py", line 174, in start_advertising
    advertisement_bytes = bytes(advertisement)
TypeError: __bytes__ returned non-bytes (type bytearray)

Circuitpython in HASS

Are there any plans to support this bluetooth to mqtt gateway bt-mqtt-gateway or any other software to use a circuitpython device in a home automated system.

I've no idea how this Bluetooth stuff works. Characteristics, Service, Descriptor puhh.
Otherwise i would start writing a so called 'worker' for the bt-mqtt-gateway.

It would be awesome to embed a circuitpython device into an existing HASS System.

Implement __eq__ for Advertisement

Implementing __eq__ method for Advertisement class will allow them to be compared in a useful way. Documention on how this works when some fields are not set would be useful.

Interim workaround is bytes(ad1) == bytes(as2)

First mentioned in comments in #79.

soft device error: 0004 when paring with BLE HID peripheral

I'm trying to get the BLE HID central to play (I just need the event report bytes). HID needs pairing and when I try to pair I get the following error and then the BT connection just times out:

Traceback (most recent call last):
  File "code.py", line 40, in <module>
  File "adafruit_ble/__init__.py", line 143, in pair
_bleio.BluetoothError: Unknown soft device error: 0004

The code I use is the following

import _bleio
import board
import time
# import usb_hid

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.standard.hid import HIDService

# keyboard = usb_hid.devices[0]

# keyboard.send_report()

ble = BLERadio()
bleHid = None

# _bleio.adapter.erase_bonding()
if ble.connected:
    for conn in ble.connections:
        conn.disconnect()
        # if HIDService in conn:
        #     bleHid = conn
        #     break

while True:
    if not bleHid:
        print("Scanning...")
        for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=5, extended=True):
            print(f"Discovered '{adv.complete_name}'")

            conn = ble.connect(adv)
            if HIDService in conn:
                print("Found HID service advertisement!")
            else:
                conn.disconnect()
                continue

            if not conn.paired:
                print("Pairing...")
                conn.pair()
                print("Paired")

            print("Putting keyboard in boot report mode")
            print(conn[HIDService].protocol_mode)
            conn[HIDService].protocol_mode = 0
            print(conn[HIDService].protocol_mode)

            bleHid = conn

            break

        ble.stop_scan()

    while bleHid and bleHid.connected:
        # print(bleHid[HIDService].boot_keyboard_out)
        data = bleHid[HIDService].boot_keyboard_out
        # data = bleHid[HIDService].devices[0].report
        # print(conn._constructed_services)
        data_int = int.from_bytes(data, "big")
        # print(data_int)
        if data_int != 0:
            print(data)
        # time.sleep(0.2)

    time.sleep(0.2)

I tried # _bleio.adapter.erase_bonding() just in case the flash is full at the address that pairings take place but it didn't work (same exact error). I'm starting to think that this is a circuitpython error?

I'm on an nrf52840 btw and the peripheral is known to work flawlessly.

apple notifications - soft device error

I tried the ble_apple_notifications.py demo on a CPB with 5.0Beta.1
this error occurred


Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 5.0.0-beta.1 on 2019-12-10; Adafruit Circuit Playground Bluefruit with nRF52840
>>> import ble_apple_notifications
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ble_apple_notifications.py", line 15, in <module>
  File "adafruit_ble/__init__.py", line 174, in start_advertising
_bleio.BluetoothError: Unknown soft device error: 0007
>>> 

same error on a feather_nRF52840 express
updated to 3.1.1 -- still same error

ble_bluefruit_connect_plotter.py should have delay in sending loop

In the "ble_bluefruit_connect_plotter.py" example, the code is sending sensor data as fast as possible both on the "console" and the BLE UART.

Reading information about Bluefruit LE connect application and the plotter function, I find recommendation of not sending too much/fast data: https://learn.adafruit.com/bluefruit-le-connect/plotter

It might also be wrong to send so much on the "console" and my Mu editor was a bit unresponsive when running that example.

I believe there should be a delay in that loop.

PS: This should be another issue... but to be compatible with Mu editor plotter function, it would be interesting to print a tuple on the console "(x, y)" rather than "x y".

Alpha2 breaking changes

Looks like 5.0.0 Alpha 2 breaks the BLE examples. I tried changing the bleio references to _bleio but I'm still having a problem with UART_Server. Here's an example:

from adafruit_ble.uart_server import UARTServer
uart_server = UARTServer()

Throws error:

File "adafruit_ble/uart_server.py", line 62, in init
TypeError: cannot create 'Characteristic' instances

BLE HID paired connections not working on some Windows 10 peripherals

Copied from adafruit/circuitpython#1050.

@urish:

Windows 10 does see the device (even though not always - I had to remove the scan_response part from the advertising so that it show it on the list of pairable devices), but disconnects about one second after pairing with a "Driver error" message:

image

Android works well

@mscosti:

@urish I'm seeing the same thing as you. At first I thought this was related to changes I have made in an attempt to implement a different HID device incorrectly / missing something (Microsoft Radial Controller / Surface Dial) , But after seeing your report I loaded up this BLE HID Keyboard example verbatim and am seeing the same behavior on Windows 10. Same thing, where it takes a second or two for it to settle with "Driver error".

image

Android Recognizes the keyboard and am able to type on it as expected

start_advertising() got an unexpected keyword argument 'timeout'

I have run ble_uart_echo_test.py and got this error

Traceback (most recent call last):
  File "echoTest.py", line 10, in <module>
    ble.start_advertising(advertisement)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_ble/__init__.py", line 212, in start_advertising
    timeout=0 if timeout is None else timeout,
TypeError: start_advertising() got an unexpected keyword argument 'timeout'

Does advertising.standard.ManufacturerDataField.field_names currently serve a purpose?

Correct me where I'm wrong:

The two possible ways to pack multiple bits of (manufacturer) data into an advertisement are

  1. create multiple ManufacturerDataField() items in your ad class.
    Pro: you get to access that data with AlexsAd.firstdataitem syntax, and you get to include-or-not items as you see fit per-broadcast.
    Con: Costs a few bytes to include the data type ID before the data item in the ad.
  2. create a single ManufacturerDataField() item, with a format that includes however many fields, all of which must be populated for any given ad.
    Pro: Saves having to spend a couple bytes per field
    Con: Have to access with AlexsAd.data[index] where you simply have to know the relevance of data at a given index, and data must have some rational "null" value that indicates "I never set that" like 0 for battery voltage, or -1 for "firefighters on scene"

Assuming I understand that architecture right, what purpose does the self.field_names object serve in advertising.standard.ManufacturerDataField on

?

It seems to add some structure and convenience about what the different indices in a ManufacturerDataField tuple mean, but also there doesn't seem to be any actual way to use that. The field_names must be defined at the class level for the class to function right, but then the values passed serve no purpose from that point on other than to consume memory (do they even?).

UARTServer does not handle writes of >20 bytes

UARTServer.write just writes a the TX Characteristic value directly. If the size of the byte buffer is too large (> 20 bytes), the write will fail. In addition, writing lots of shorter byte buffers will fail because we aren't waiting for the ack. It should do the write in a buffered way to allow longer buffers to be written.

Thanks to @dastels for uncovering this.

Gamepad not supported as BLE HID device

from adafruit_ble.services.standard.hid import HIDService
from adafruit_hid.gamepad import Gamepad

hid = HIDService()
gp = Gamepad(hid.devices)

This returns an error:

Traceback (most recent call last):
  File "code.py", line 5, in <module>
  File "adafruit_hid/gamepad.py", line 55, in __init__
  File "adafruit_hid/__init__.py", line 56, in find_device
ValueError: Could not find matching HID device.

While using keyboard/mouse works fine. Is gamepad not supported as a BLE HID device?

IBeacon test

FYI -- using the Manufacturer ID 0x004C - Apple for the beacon test works well with the IOS Locate Beacon App

from adafruit_ble.uuid import UUID
test_uuid = UUID('12345678-1234-1234-1234-123456789abc')
test_company = 0x004c
b = LocationBeacon(test_company, test_uuid,123, 234, -54)
b.start()

UART ECHO TEST failure

screen shot 2019-01-11 at 6 35 56 am
@dhalbert do you want these type of issues here or agianst CP?
I think I can repodce this -- at least it did it twice when I tried to send more than 24 characters
See attached screenshot - it failed during the third line


Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 4.0.0-alpha.5-120-g573c6d60b on 2019-01-11; Particle Argon with nRF52840
>>> 
>>> 
>>> import ble_uart_echo_test
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ble_uart_echo_test.py", line 10, in <module>
  File "adafruit_ble/uart.py", line 72, in write
  File "adafruit_ble/characteristic.py", line 110, in value
OSError: Failed to notify or indicate attribute value, err 1304x
>>> 

Reproduced a few more times -- it failed on the 24th character these times

It may be that this is just pushing the test too hard -- This is right around the limit for a BLE packet.

Unknown soft device error: 0012 (when trying to connect multiple devices)

This is really cool project! I want to connect multiple device.
But, I can't connect 3 or more devices. Here is a code and error message.
I tried CurrentTimeService and ANCS, and both give the same error message.

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import SolicitServicesAdvertisement
from adafruit_ble.services.standard import CurrentTimeService

r = BLERadio()

r.start_advertising(SolicitServicesAdvertisement(CurrentTimeService))

# after tapping this device name on the 1st iOS
r.connections[-1].pair()

r.start_advertising(SolicitServicesAdvertisement(CurrentTimeService))

# after tapping this device name on the 2nd iOS
r.connections[-1].pair()

#### this advertising fails ###
r.start_advertising(SolicitServicesAdvertisement(CurrentTimeService))

# after tapping this device on the 3rd iOS
r.connections[-1].pair()
>>> r.start_advertising(SolicitServicesAdvertisement(CurrentTimeService))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "adafruit_ble/__init__.py", line 174, in start_advertising
_bleio.BluetoothError: Unknown soft device error: 0012

I use REPL on
feather_nrf52840_express_bootloader-0.2.13_s140_6.1.1.zip
adafruit-circuitpython-bundle-5.x-mpy-20200109.zip

Expose ADAFRUIT_COMPANY_ID and MANUFACTURING_DATA_ADT

_MANUFACTURING_DATA_ADT and _ADAFRUIT_COMPANY_ID are defined in

_MANUFACTURING_DATA_ADT = const(0xFF)
_ADAFRUIT_COMPANY_ID = const(0x0822)
as 0xFF and 0x0822, respectively. The underscore prefix in conjunction with the use of const() (@dhalbert clarified this) makes them truly private and unusable from elsewhere.

These reference values would be useful to expose from somewhere in adafruit_ble library for other code which is creating packets, e.g.

These currently have their own local variables with these values.

prefix building

Currently the advertising prefix mechanism requires counting bytes and manually including a length. I was thinking about some helper functions for this. Straw ideas:

class SomeAdvertisement(Advertisement):
    prefix = Advertisement.prefixes(<prefix>, <prefix>, ...)

The class method would add length headers and merge into a single bytes
and maybe also include any/all matching designation in a Prefix object:

    prefix = Advertisement.Prefix.match_any(...)
...
    prefix = Advertisement.Prefix.match_all(...)

The prefix class-variable name might be renamed to prefixes or match_prefixes, since it's actually multiple prefixes.

uuid module missing

I am unable to test the ibeacon since the uuid.py module is missing

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 4.0.0-alpha.5-207-gf46ec0253 on 2019-01-22; Adafruit Feather nRF52840 Express with nRF52840
>>> 
>>> import ibeacon
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "ibeacon.py", line 2, in <module>
ImportError: no module named 'adafruit_ble.uuid'
>>> import ibeacon

Fails with asyncio exception on Mac

Installed the module (Python 3.7, MacOS 10.15) according to the instructions in the readme file. Installed in a virtual environment.

Tried to run the example code (again from the readme).

I get a RuntimeError from asyncio:

Traceback (most recent call last):
  File "test.py", line 6, in <module>
    for entry in radio.start_scan(timeout=60, minimum_rssi=-80):
  File "/Users/jack/tmp/venv-ble/.env/lib/python3.7/site-packages/adafruit_ble/__init__.py", line 271, in start_scan
    active=active,
  File "/Users/jack/tmp/venv-ble/.env/lib/python3.7/site-packages/_bleio/adapter_.py", line 214, in start_scan
    self._scan_for_interval(scanner, self._SCAN_INTERVAL)
  File "/Users/jack/tmp/venv-ble/.env/lib/python3.7/site-packages/_bleio/adapter_.py", line 114, in await_bleak
    return future.result(timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 432, in result
    return self.__get_result()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/concurrent/futures/_base.py", line 384, in __get_result
    raise self._exception
  File "/Users/jack/tmp/venv-ble/.env/lib/python3.7/site-packages/_bleio/adapter_.py", line 312, in _scan_for_interval
    await scanner.start()
  File "/Users/jack/tmp/venv-ble/.env/lib/python3.7/site-packages/bleak/backends/corebluetooth/scanner.py", line 47, in start
    await self._manager.wait_for_powered_on(0.1)
  File "/Users/jack/tmp/venv-ble/.env/lib/python3.7/site-packages/bleak/backends/corebluetooth/CentralManagerDelegate.py", line 106, in wait_for_powered_on
    await asyncio.wait_for(self.powered_on_event.wait(), timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/tasks.py", line 416, in wait_for
    return fut.result()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/locks.py", line 293, in wait
    await fut
RuntimeError: Task <Task pending coro=<Event.wait() running at /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/locks.py:293> cb=[_release_waiter(<Future pendi...5305c46d8>()]>)() at /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/tasks.py:366]> got Future <Future pending> attached to a different loop

Trying to get my feather sense to send data to my desktop, seem to be missing something

Hi,
I'm trying to get data from my feather sense sent to my desktop over BLE but I seem to be missing something. Currently just trying to send over the counts.

I've also recorded a video explanation to help as well. https://youtu.be/I14jim7SfaE

I'm new to the circuit python world so I may be missing something obvious. Any tips or pointers as to what that could be would be helpful.

Thanks in advance

Details

Here's what my code.py on the device looks like.

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
# from adafruit_ble.uart_server import UARTServer
 
ble = BLERadio()
uart_server = UARTService()
advertisement = ProvideServicesAdvertisement(uart_server)
 
 
while True:
    ble.start_advertising(advertisement)
    print("Waiting to connect")
    while not ble.connected:
        pass
    print("Connected")
    
    i = 0
    while ble.connected:
        i += 1
        result = f"Hi from feather {i}"
        print(result)
        uart_server.write(result.encode())
        time.sleep(1)

I copied it from this example in this pdf https://readthedocs.org/projects/adafruit-circuitpython-bluefruitconnect/downloads/pdf/latest/

Documentation

image

Central and packet capture

On the central side, my Ubuntu desktop. I seem to be receiving the packets for pairing and disconnecting, but nothing else. I am using this command to create the packet capture

tcpdump -vv -i bluetooth0 -w bluetooth0_capture_gh_issue.pcap

image

Ive attached the packet dump as well in case it means anything
bluetooth0_capture_gh_issue.pcap.zip

Versions

Adafruit BLE 7.3.1
Adafruit CircuitPython 5.3.1 on 2020-07-13; Adafruit Feather Bluefruit Sense with nRF52840

A custom Advertisement with a constructor can fail to parse incoming BLE data correctly

This innocent looking constructor in a sub-class of Advertisement:

    def __init__(self, enc_data=None, round=0):
        super().__init__()
        if enc_data is not None:
            self.enc_data = enc_data
        if round is not None:
            self.round = round

was causing ads to be receieved on another Adafruit device use this library as

<RpsEncDataAdvertisement manufacturer_data=<ManufacturerData company_id=0822 data=03 31 ff 00 > >

Minor possibility I've misdiagnosed this and they are sent like this due to a bug but this seems unlikely.

Originally mentioned in the comments of #79 (comment)

start_scan(): if no Advertisements are given, nothing is returned.

This recent changed to the code in start_scan():

            # Double check the adv_type is requested. We may return Advertisement accidentally
            # otherwise.
            if adv_type not in advertisement_types:
                continue

means that if no advertisement_types are given, no advertisements at all will be returned by start_scan(), so it appears as if nothing is advertising. Previously, all received advertisements would be returned as Advertisement objects.

@tannewt I thought I understand your change in #72, but now I realize I didn't.

I think advertisement_types should be set to (Advertisement,) if it comes in as empty.

Add Advertisement length checking.

Now that extended Advertisements are allowed, check Advertisement lengths, and allow longer Advertisements if a flag parameter is set, but complain otherwise. Flag name could be extended_supported, extended_allowed or similar.

Fails to import on nRF52840 Express

CircuitPython cannot import the adafruit_ble library.

Platform: Adafruit Feather nRF52840 Express (https://www.adafruit.com/product/4062)

CircuitPython Version: 4.x.x and 5.x.x

Steps to Reproduce:
Flashed firmware and copy/pasted code according the instructions in this tutorial:
https://learn.adafruit.com/ble-hid-keyboard-buttons-with-circuitpython/ble-keyboard-buttons-libraries-and-code

Expected Result:
Feather will become available for BLE pairing

Actual Result:

code.py output:
Traceback (most recent call last):
  File "code.py", line 10, in <module>
  File "adafruit_ble/__init__.py", line 33, in <module>
ImportError: This release is not compatible with CircuitPython 4.x; use library release 1.x.x

simple scan not receiving ble devices on raspberry pi 4

I'm running raspbian on raspberry pi 4 and simple scan example is not receiving my ble device that is advertising. I do receive it with hcitool on the raspberry pi 4

pi@raspberrypi:~/Desktop/raspi_bluetooth $ sudo hcitool lescan
LE Scan ...
F4:CF:A2:8D:30:FA (unknown)
F4:CF:A2:8D:30:FA (unknown)

The simple scan example I'm running in python is

# SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

from adafruit_ble import BLERadio

ble = BLERadio()
print("scanning")
found = set()
scan_responses = set()
for advertisement in ble.start_scan():
    addr = advertisement.address
    if advertisement.scan_response and addr not in scan_responses:
        scan_responses.add(addr)
    elif not advertisement.scan_response and addr not in found:
        found.add(addr)
    else:
        continue
    print(addr, advertisement)
    print("\t" + repr(advertisement))
    print()

print("scan done")

ComplexCharacteristic does not pass fixed_length instance variable to _bleio.Characteristic.add_to_service

This does not pass a keyword arg of fixed_length and therefore picks up a False default value:

return _bleio.Characteristic.add_to_service(
service.bleio_service,
self.uuid.bleio_uuid,
initial_value=self.initial_value,
max_length=self.max_length,
properties=self.properties,
read_perm=self.read_perm,
write_perm=self.write_perm,
)

The class does have an instance variable of fixed_length - it looks like this was intended to be passed?

High CPU usage with BLEUART

There is high CPU usage observed when reading bytes from BLEUART connection. With modified (bigger) buffer size in adafruit_ble/services/nordic.py, if I read 180 bytes of BLE buffer in about 50 times per second, that uses the total CPU about 20%-25% with RaspberryPi4. RPi4 has 4 cores so that means it uses the single core about 80% to 100% percent.

Current configuration:

Raspberry Pi OS: 5.4.72-v7l+
Adafruit_CircuitPython_BLE: 7.3.1
Adafruit_Blinka_bleio: 2.0.4
Bluez: 5.50-1.2~deb10u1+rpt2

Long Advertisement messages don't appear to be received by start_scan()

There's an inconsistency here between behaviour of short and long Advertisement packets presumably due to the handling somewhere of extended advertising. I'm not sure if this is at transmit or receieve end. This is on 5.3.0

Device A:

>>> from adafruit_ble import BLERadio
>>> from adafruit_ble.advertising import Advertisement
>>> ble = BLERadio()
>>> from adafruit_ble.advertising.adafruit import AdafruitColor
>>> acad = AdafruitColor()
>>> acad.color = 0x112233
>>> acad.short_name = "Short name"
>>> ble.start_advertising(acad)

Device B (looks good):

>>> from adafruit_ble import BLERadio
>>> from adafruit_ble.advertising import Advertisement
>>> ble = BLERadio()
>>> for adv in ble.start_scan(Advertisement, timeout=2):
...     print(adv)
...
...
...
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement tx_power=0 >
<Advertisement short_name=Short name >
<Advertisement short_name=Short name >
<Advertisement short_name=Short name >

Device A (make packet bigger, i.e. > 31 bytes):

>>> ble.stop_advertising()
>>> acad.short_name = "A not so short name intended to push the packet size over 31 bytes"
>>> acad
Advertisement(data=b"\x43\x08\x41\x20\x6e\x6f\x74\x20\x73\x6f\x20\x73\x68\x6f\x72\x74\x20\x6e\x61\x6d\x65\x20\x69\x6e\x74\x65\x6e\x64\x65\x64\x20\x74\x6f\x20\x70\x75\x73\x68\x20\x74\x68\x65\x20\x70\x61\x63\x6b\x65\x74\x20\x73\x69\x7a\x65\x20\x6f\x76\x65\x72\x20\x33\x31\x20\x62\x79\x74\x65\x73\x0a\xff\x22\x08\x06\x00\x00\x33\x22\x11\x00")
>>> ble.start_advertising(acad)

Radio silence on device B:

>>> for adv in ble.start_scan(Advertisement, timeout=2):
...     print(adv)
...
...
...

CircuitPython Locks Up on Disconnect

Using the current time service example on a Adafruit Feather nRF52840 Sense with CircuitPython 5.3 (and on 5.4-beta1):

https://github.com/adafruit/Adafruit_CircuitPython_BLE/blob/master/examples/ble_current_time_service.py

I connected the sense with my android phone running the Nordic nRF Connect for Mobile app.

Upon connecting to the sense, it proceeds to print the current time. If you disconnect from the sense via the app (close the tab), depending upon the timing of the disconnect, the sense will either print disconnected, as expected, or lock-up. When it's locked up, it appears that its hung up on the cts.current_time statement (line 28). Because of the delay between the time the app disconnects from the sense and the time the sense detects the disconnect, the program attempts to retrieve the current time even though it is really disconnected. You can increase the odds of reproducing this by changing time.sleep(1) in line 29 to time.sleep(0.1).

When locked-up, it becomes unresponsive and you have to manually reset the board.

ValueError: Bad checksum

Traceback (most recent call last):
File "code.py", line 241, in
File "/home/travis/build/adafruit/Adafruit_CircuitPython_Bundle/libraries/helpers/bluefruitconnect/adafruit_bluefruit_connect/packet.py", line 128, in from_stream
File "/home/travis/build/adafruit/Adafruit_CircuitPython_Bundle/libraries/helpers/bluefruitconnect/adafruit_bluefruit_connect/packet.py", line 89, in from_bytes
ValueError: Bad checksum

BLE scanning timeout ignored on nRF52840

I set up a little color sender example as a debug exercise. This is the receive side of it (The send side is commented out):

# Color Sender

import time
import board
import digitalio

import neopixel

from adafruit_ble import BLERadio
from adafruit_ble.advertising.adafruit import AdafruitColor

# The color pickers will cycle through this list with buttons A and B.
color_options = [
    0x110000,
    0x111100,
    0x001100,
    0x001111,
    0x000011,
    0x110011,
    0x111111,
    0x221111,
    0x112211,
    0x111122,
]

ble = BLERadio()

button = digitalio.DigitalInOut(board.SWITCH)
button.pull = digitalio.Pull.UP                     # Button is active LOW

led = digitalio.DigitalInOut(board.D13)
led.switch_to_output()

neopixels = neopixel.NeoPixel(board.NEOPIXEL, 10, auto_write=False)

i = 0
advertisement = AdafruitColor()
advertisement.color = color_options[i]
neopixels.fill(color_options[i])
closest_last_time = time.monotonic()
neopixels.fill(0x000000)
neopixels.show()
while True:
    # The first mode is the color selector which broadcasts it's current color to other devices.
    # print("Broadcasting color")
    # ble.start_advertising(advertisement)
    # last_i = i
    # if not button.value:            # Active low.
    #     i += 1
    # i %= len(color_options)
    # if last_i != i:
    #     color = color_options[i]
    #     neopixels.fill(color)
    #     print("New color {:06x}".format(color))
    #     neopixels.fill(0x000000)
    #     neopixels[0] = color
    #     neopixels.show()
    #     advertisement.color = color
    #     ble.stop_advertising()
    #     ble.start_advertising(advertisement)
    #     time.sleep(0.5)
    # ble.stop_advertising()
    # The second mode listens for color broadcasts and shows the color it hears.
    print("Scanning for colors")
    for entry in ble.start_scan(AdafruitColor, minimum_rssi=-100, timeout=1):
        closest_last_time = time.monotonic()
        print(entry.rssi, entry.color)
        neopixels.fill(0x000000)
        neopixels[0] = entry.color
        neopixels.show()
        ble.stop_scan()
    print("out of loop")
    # Clear the pixels if we haven't heard from anything recently.
    now = time.monotonic()
    if now - closest_last_time > 1:
        neopixels.fill(0x000000)
        neopixels.show()
    ble.stop_scan()

Note ble.stop_scan() at the end of the for entry in ble.start_scan(AdafruitColor, minimum_rssi=-100, timeout=1): section.

With that stop_scan() present, of course it stops scanning every advert it hears, and I get the following output:

Scanning for colors
-41 1114112
out of loop
Scanning for colors
-52 1114112
out of loop
Scanning for colors

If I remove the ble.stop_scan(), expecting the start_scan() to return after 1s, it simply never does. print("out of loop") just never happens.

Maybe the underlying implementation on nRF is buggy and this is actually a circuitpython issue?

Advertising scan fails

After updating to the latest version, my script began crashing with the following stack:

...
File "<redacted>/lib/python3.7/site-packages/adafruit_ble/__init__.py", line 268, in start_scan
    advertisement = adv_type(entry=entry)
File "<redacted>/lib/python3.7/site-packages/adafruit_ble/advertising/standard.py", line 167, in __init__
    self.flags.general_discovery = True
AttributeError: 'NoneType' object has no attribute 'general_discovery'

Perhaps related to the lazy object instantiation of self.flags from the parent class.

Reverting to version 7.3.4 fixes the problem.

BLE HID does not work on Raspberry Pi

I'm trying to port this tutorial to my raspberry pi zero, but upon running the script I get the following error:

Traceback (most recent call last):
  File "code.py", line 22, in <module>
    hid = HIDService()
  File "/usr/local/lib/python3.7/dist-packages/adafruit_ble/services/standard/hid.py", line 324, in __init__
    super().__init__(report_map=hid_descriptor)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_ble/services/__init__.py", line 70, in __init__
    getattr(self, class_attr)
  File "/usr/local/lib/python3.7/dist-packages/adafruit_ble/characteristics/__init__.py", line 142, in __get__
    return bleio_characteristic.value
  File "/usr/local/lib/python3.7/dist-packages/_bleio/characteristic.py", line 183, in value
    self.service.connection._bleak_client.read_gatt_char(self.uuid._bleak_uuid)
AttributeError: 'NoneType' object has no attribute '_bleak_client'

This seems to be pretty far down the stack, so I'm finding it very difficult to debug. Does anyone have any tips on what could be the issue? Is it a fundamental hardware issue or can I tweak the code to make it run on my raspi0. I'm not very well versed in BLE, so I was hoping someone with more expertise could maybe offer some insight. I'd greatly appreciate any help :)

Hang when disconnecting quickly

When one side of the connection disconnects abruptly, the code can hang with the following error:

Traceback (most recent call last):
  File "code.py", line 25, in <module>
  File "adafruit_ble/uart_server.py", line 142, in write
OSError: Failed to read CCCD value, err 0x3002

Requires soft reset to continue.

Mentioned to @dhalbert who suggested filing an issue here, though it is still unclear whether or not this should be handled within this library or within CircuitPython itself.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.