Giter Club home page Giter Club logo

pygatt's Introduction

pygatt - Python Module for Bluetooth LE Generic Attribute Profile (GATT).

This Module allows reading and writing to GATT descriptors on devices such as fitness trackers, sensors, and anything implementing standard GATT Descriptor behavior.

pygatt provides a Pythonic API by wrapping two different backends:

  • BlueZ (requires Linux), using the gatttool command-line utility.
  • Bluegiga's BGAPI, compatible with USB adapters like the BLED112.

Motivation

Despite the popularity of BLE, we have yet to find a good programming interface for it on desktop computers. Since most peripherals are designed to work with smartphones, this space is neglected. One interactive interface, BlueZ's gatttool, is functional but difficult to use programmatically. BlueZ itself obviously works, but the interface leaves something to be desired and only works in Linux.

Requirements

  • Python 2.7.5 or greater, or Python 3.5 or greater
    • Python 2.7.3's struct library has a bug that will break PyGATT - 2.7.5
      or greater is recommended.
  • BlueZ 5.18 or greater (with gatttool) - required for the gatttool backend only.
    • Tested on 5.18, 5.21, 5.35 and 5.43
  • GATTToolBackend requires Linux and sudo (i.e. not Windows compatible)

Installation

Install pygatt with pip from PyPI:

$ pip install pygatt

The BlueZ backend is not supported by default as it requires pexpect, which can only be installed in a UNIX-based environment. If you wish to use that backend, install the optional dependencies with:

$ pip install "pygatt[GATTTOOL]"

Install the latest development version of pygatt with pip:

$ pip install git+https://github.com/peplin/pygatt

Documentation

The documentation for pygatt consists of:

  • This README
  • The code in the samples directory
  • The Python docstrings in the code itself.

The BLEDevice and BLEBackend base classes are the primary interfaces for users of the library.

Known Issues

  • Performance has not been profiled, and there have been reports that both GATTTool and BGAPI backends struggled to handle high rate notifications (e.g. > 100Hz).
  • There is no way for the user to be notified if a device disconnects asynchronously (#306).
  • PIN-based authentication is not supported.
  • Duplicate characteristic names across different BLE service UUIDs are not supported.
  • Long characteristic reads and writes are only supported by the BGAPI backend.

Example Use

The primary API for users of this library is provided by pygatt.BLEBackend and pygatt.BLEDevice. After initializing an instance of the preferred backend (available implementations are found in pygatt.backends, use the BLEBackend.connect method to connect to a device and get an instance of BLEDevice.

import pygatt

# The BGAPI backend will attempt to auto-discover the serial device name of the
# attached BGAPI-compatible USB adapter.
adapter = pygatt.BGAPIBackend()

try:
    adapter.start()
    device = adapter.connect('01:23:45:67:89:ab')
    value = device.char_read("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b")
finally:
    adapter.stop()

Note that not all backends support connecting to more than 1 device at at time, so calling BLEBackend.connect again may terminate existing connections.

Here's the same example using the GATTTool backend. It's identical except for the initialization of the backend:

import pygatt

adapter = pygatt.GATTToolBackend()

try:
    adapter.start()
    device = adapter.connect('01:23:45:67:89:ab')
    value = device.char_read("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b")
finally:
    adapter.stop()

Notifications Example

This example uses the gatttool backend to connect to a device with a specific MAC address, subscribes for notifications on a characteristic, and prints the data returned in each notification.

import pygatt
from binascii import hexlify

adapter = pygatt.GATTToolBackend()

def handle_data(handle, value):
    """
    handle -- integer, characteristic read handle the data was received on
    value -- bytearray, the data returned in the notification
    """
    print("Received data: %s" % hexlify(value))

try:
    adapter.start()
    device = adapter.connect('01:23:45:67:89:ab')

    device.subscribe("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b",
                     callback=handle_data)

    # The subscription runs on a background thread. You must stop this main
    # thread from exiting, otherwise you will not receive any messages, and
    # the program will exit. Sleeping in a while loop like this is a simple
    # solution that won't eat up unnecessary CPU, but there are many other
    # ways to handle this in more complicated program. Multi-threaded
    # programming is outside the scope of this README.
    while True:
        time.sleep(10)
finally:
    adapter.stop()

Debugging

While debugging software using pygatt, it is often useful to see what's happening inside the library. You can enable debugging logging and have it printed to your terminal with this code:

import pygatt
import logging

logging.basicConfig()
logging.getLogger('pygatt').setLevel(logging.DEBUG)

Random Addressing

If you are having trouble connecting to a device, it may use random addressing. Try changing the connection setup code to:

device = adapter.connect('01:23:45:67:89:ab', address_type=pygatt.BLEAddressType.random)

Unexplained Timeouts

If you are experiencing unexplained timeouts with the gatttool backend, you may need to increase the supervisor timeouts:

echo 1000 > /sys/kernel/debug/bluetooth/hci0/supervision_timeout

Can't find BGAPI device in Windows

You may need to explicitly specify the COM port of your BGAPI-compatible device in windows, e.g.:

adapter = pygatt.BGAPIBackend(serial_port='COM9')

If you provide the COM port name, but still get an error such as WindowsError(2, 'The system cannot find the file specified.'), try changing the COM port of the device to a value under 10, e.g. COM9.

Authors

Releasing to PyPI

For the maintainers of the project, when you want to make a release:

  • Merge all of the changes into master.
  • Update the version in setup.py.
  • Update the CHANGELOG.mkd
  • Tag the commit and push to GitHub (will need to push to a separate branch of PR first since master is a protected branch).
  • Travis CI will take care of the rest - it will build and deploy tagged commits to PyPI automatically.

License

Copyright 2015 Stratos Inc. and Orion Labs

Apache License, Version 2.0 and MIT License. See LICENSE.

pygatt's People

Contributors

3sigma avatar alexandrebarachant avatar ampledata avatar coimbra1984 avatar dcliftreaves avatar designingsparks avatar e-yes avatar hbldh avatar ilyasukhanov avatar lachtanek avatar lchish avatar lepot311 avatar luzpaz avatar m-georgi avatar mdxs avatar michelrivas avatar mitchellrj avatar msaunby avatar ndoss123 avatar peplin avatar phooji avatar rhempel avatar ryanhsutw avatar sandlerb avatar sloboste avatar thomafred avatar tommybobbins avatar tubaman avatar voxvalve avatar wdoganowski avatar

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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pygatt's Issues

AttributeError

Hi, I'm perfectly able to connect to my BLE device using gatttool, pygatt however returns this error, using the example code mentioned on this GitHub page.
pi@raspberrypi:~ $ python PyGATT.py DEBUG:pygatt.backends.gatttool.gatttool:gatttool_cmd=gatttool -i hci0 -I INFO:pygatt.backends.gatttool.gatttool:Running... INFO:pygatt.backends.gatttool.gatttool:Connecting to d4:1c:f5:9d:a4:7e with timeout=5 INFO:pygatt.backends.gatttool.gatttool:Stopping INFO:pygatt.backends.gatttool.gatttool:Listener thread finished Traceback (most recent call last): File "PyGATT.py", line 10, in <module> device = adapter.connect('d4:1c:f5:9d:a4:7e', 5, 'random') File "/usr/local/lib/python2.7/dist-packages/pygatt/backends/gatttool/gatttool.py", line 319, in connect cmd = 'connect {0} {1}'.format(self._address, address_type.name) AttributeError: 'str' object has no attribute 'name'

Feature Request: Filter out specific names -> (unknown)

my BLE devices (RGB bulbs) annonces two "names", one with a real name "Nexturn" and one (unknown) line. It is possible to filter out unwanted names ("unknown") in my case.

>>> pygatt.lescan()
[{'name': 'Nexturn', 'address': 'D0:39:72:A1:D2:58'}, {'name': 'Nexturn', 'address': '90:59:AF:2A:C7:B8'}, {'name': 'Nexturn', 'address': 'D0:39:72:A1:B8:D0'}]
>>> pygatt.lescan()
[{'name': 'Nexturn', 'address': 'D0:39:72:A1:D2:58'}, {'name': '(unknown)', 'address': '90:59:AF:2A:C7:B8'}, {'name': 'Nexturn', 'address': 'D0:39:72:A1:B8:D0'}]
# hcitool lescan
LE Scan ...
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
90:59:AF:2A:C7:B8 (unknown)
90:59:AF:2A:C7:B8 Nexturn
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
D0:39:72:A1:B8:D0 (unknown)
D0:39:72:A1:B8:D0 Nexturn
90:59:AF:2A:C7:B8 (unknown)
90:59:AF:2A:C7:B8 Nexturn
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
D0:39:72:A1:B8:D0 (unknown)
D0:39:72:A1:B8:D0 Nexturn
90:59:AF:2A:C7:B8 (unknown)
90:59:AF:2A:C7:B8 Nexturn
D0:39:72:A1:D2:58 (unknown)

_hex_value_parser of gatttool.py fails on python 3.5

Hi,

I'm currently trying to talk to a BLE device using the pygatt library using the GATTTool backend. I was always getting timeouts connecting, but the device apparently did, what I wanted. So I started digging. I found out that the _hex_value_parser doesn't work on my "Python 3.5.2+ (default, Dec 13 2016, 14:16:35)" debian testing install.

Here is what happens (with pexpect logging to stdout):

[                 ][LE]> connect 00:1A:22:09:AE:D5 public
connect 00:1A:22:09:AE:D5 public
Attempting to connect to 00:1A:22:09:AE:D5
Connection successful
[00:1A:22:09:AE:D5][LE]> char-write-req 0x411 4128
char-write-req 0x411 4128
Characteristic value was written successfully
[00:1A:22:09:AE:D5][LE]> sec-level low
sec-level low
[00:1A:22:09:AE:D5][LE]> connect 00:1A:22:09:AE:D5 public
connect 00:1A:22:09:AE:D5 public
Notification handle = 0x0421 value: 02 01 09 00 04 22 
[00:1A:22:09:AE:D5][LE]> 
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.5/threading.py", line 914, in _bootstrap_inner
    self.run()
  File "/usr/local/lib/python3.5/dist-packages/pygatt/backends/gatttool/gatttool.py", line 120, in run
    event["callback"](event)
  File "/usr/local/lib/python3.5/dist-packages/pygatt/backends/gatttool/gatttool.py", line 422, in _handle_notification_string
    values = _hex_value_parser(hex_values)
  File "/usr/local/lib/python3.5/dist-packages/pygatt/backends/gatttool/gatttool.py", line 29, in _hex_value_parser
    return bytearray.fromhex(x.decode('utf8'))
AttributeError: 'str' object has no attribute 'decode'

Line numbers may be a little off, because of my debugging stuff in it.

If I use the "python 2.7 implementation" of the _hey_value_parser, it doesn't crash anymore, but it still tells me that a timeout occured while connecting, even though the request as been sent correctly and the notification handle answer looks okay:

[                 ][LE]> sec-level low
sec-level low
[                 ][LE]> connect 00:1A:22:09:AE:D5 public
connect 00:1A:22:09:AE:D5 public
Attempting to connect to 00:1A:22:09:AE:D5
Connection successful
[00:1A:22:09:AE:D5][LE]> char-write-req 0x411 4126
char-write-req 0x411 4126
Characteristic value was written successfully
[00:1A:22:09:AE:D5][LE]> sec-level low
sec-level low
Notification handle = 0x0421 value: 02 01 09 00 04 26 
[00:1A:22:09:AE:D5][LE]> connect 00:1A:22:09:AE:D5 public
connect 00:1A:22:09:AE:D5 public
[00:1A:22:09:AE:D5][LE]> Timed out connecting to 00:1A:22:09:AE:D5 after 5.0 seconds.

Any ideas?
Thanks for your help in advance!
Cheers,
Manuel

Get the address for connect()

I have no idea what the address is that should be passed to the connect() method. I'm assuming this is the address of the bluetooth peripheral and not the address of the BLED112 dongle. Is there a way that I can scan for peripheral devices using pygatt? Then query for their names and addresses before connecting to them?

Connection Timeout: Trying to read multiple times

I have a series of BLE temperature sensors. I'm attempting to continuously read these sensors and output the temperatures. I understand that BLE can be fickle with maintaining connections. However, I have tried disconnected after each read then reconnecting again. This works for somewhere between 5 and 20 connections or reads (it changes each time), but then after a while every time I get a Timeout connecting.

Are there any suggestions for how I can keep the connection or close it and reopen it every time?

Unable to auto-detect BLED112 serial port

Hi, im trying to use pygatt on raspi, when i run adapter = pygatt.backends.BGAPIBackend() i get
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.4/dist-packages/pygatt/backends/bgapi/bgapi.py", line 79, in __init__ raise BGAPIError("Unable to auto-detect BLED112 serial port")
what does this mean?
i have a usb bluetooth 4 le dongle connected
im running python as sudo

No BGAPI compatible device detected

I've been playing with this a lot the last couple days. At first, I wasn't having any issues with it, but now, whenever I try to call adapter.start() I am getting an error that No BGAPI compatible device detected.

At first it worked everytime flawlessly, then for a while, if I just kept calling adapter.start() over and over, eventually on the tenth or fifteenth time it would work. Now I can't get it to recognize the dongle at all. I've tried unplugging and plugging in the dongle, restarting my PC, nothing seems to solve the issue.

Traceback (most recent call last):
  File "C:\Users\user\cabelas\pygatt\backends\bgapi\bgapi.py", line 153, in _open_serial_port
    timeout=0.25)
  File "C:\Users\user\cabelas\lib\site-packages\serial\serialwin32.py", line 31, in __init__
    super(Serial, self).__init__(*args, **kwargs)
  File "C:\Users\user\cabelas\lib\site-packages\serial\serialutil.py", line 240, in __init__
    self.open()
  File "C:\Users\user\cabelas\lib\site-packages\serial\serialwin32.py", line 78, in open
    self._reconfigure_port()
  File "C:\Users\user\cabelas\lib\site-packages\serial\serialwin32.py", line 222, in _reconfigure_port
    'Original message: {!r}'.format(ctypes.WinError()))
serial.serialutil.SerialException: Cannot configure port, something went wrong. Original message: FileNotFoundError(2, 'The system cannot find the file specified.', None, 2)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\user\cabelas\pygatt\backends\bgapi\bgapi.py", line 192, in start
    self._open_serial_port()
  File "C:\Users\user\cabelas\pygatt\backends\bgapi\bgapi.py", line 163, in _open_serial_port
    "No BGAPI compatible device detected")
pygatt.exceptions.NotConnectedError: No BGAPI compatible device detected

Any help is super appreciated.

pip install broken

Upon installing pygatt via pip yields in broken package. Import fails with following error:

>>> import pygatt.backends
Traceback (most recent call last):
File "", line 1, in
File "/home/user.virtualenvs/pexpect3_test/lib/python3.4/site-packages/pygatt/init.py", line 3, in >
from .backends import BGAPIBackend, GATTToolBackend # noqa
ImportError: No module named 'pygatt.backends'

Appears that pygatt.backends is not part of pip distribution. Missing from setup.py perhaps?

pip install -e . against source works without problems.

Unable to auto-detect BLED112 serial port on OS X

On a Mac after:

import pygatt
adapter = pygatt.BGAPIBackend()
adapter.start()

results in this error:

BGAPIError                                Traceback (most recent call last)
<ipython-input-3-9b89dcd34ca5> in <module>()
----> 1 adapter.start()

/Users/mark/anaconda2/lib/python2.7/site-packages/pygatt/backends/bgapi/bgapi.pyc in start(self)
    162             self.stop()
    163
--> 164         self._open_serial_port()
    165
    166         # Blow everything away and start anew.

/Users/mark/anaconda2/lib/python2.7/site-packages/pygatt/backends/bgapi/bgapi.pyc in _open_serial_port(self)
    134         attempts, with a short pause in between each attempt.
    135         """
--> 136         serial_port = self._serial_port or self._detect_device_port()
    137         self._ser = None
    138         for _ in range(MAX_RECONNECTION_ATTEMPTS):

/Users/mark/anaconda2/lib/python2.7/site-packages/pygatt/backends/bgapi/bgapi.pyc in _detect_device_port(self)
    120             product_id=BLED112_PRODUCT_ID)
    121         if len(detected_devices) == 0:
--> 122             raise BGAPIError("Unable to auto-detect BLED112 serial port")
    123
    124         return detected_devices[0].port_name

BGAPIError: Unable to auto-detect BLED112 serial port

GATTToolBackend fails to scan twice on same adapter

On Ubuntu 16.04 with bluez 5.43, calling scan() two times on the same GATTTool adapter systematically fails.

Here is an example script of the problem :

>>> import pygatt
>>> adapter = pygatt.GATTToolBackend()
>>> adapter.start()
>>> adapter.scan()
[{'name': None, 'address': 'A4:77:33:C2:D0:5F'}, {'name': 'BF PPG Project', 'address': 'A0:E6:F8:75:50:84'}]
>>> adapter.scan()
Unexpected error when scanning
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/pexpect/spawnbase.py", line 150, in read_nonblocking
    s = os.read(self.child_fd, size)
OSError: [Errno 5] Input/output error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/pexpect/expect.py", line 99, in expect_loop
    incoming = spawn.read_nonblocking(spawn.maxread, timeout)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/pty_spawn.py", line 465, in read_nonblocking
    return super(spawn, self).read_nonblocking(size)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/spawnbase.py", line 155, in read_nonblocking
    raise EOF('End Of File (EOF). Exception style platform.')
pexpect.exceptions.EOF: End Of File (EOF). Exception style platform.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/pygatt/backends/gatttool/gatttool.py", line 288, in scan
    scan.expect('foooooo', timeout=timeout)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/spawnbase.py", line 321, in expect
    timeout, searchwindowsize, async)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/spawnbase.py", line 345, in expect_list
    return exp.expect_loop(timeout)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/expect.py", line 105, in expect_loop
    return self.eof(e)
  File "/usr/local/lib/python3.5/dist-packages/pexpect/expect.py", line 50, in eof
    raise EOF(msg)
pexpect.exceptions.EOF: End Of File (EOF). Exception style platform.
<pexpect.pty_spawn.spawn object at 0x7f4779c2d5c0>
command: /usr/bin/hcitool
args: ['/usr/bin/hcitool', 'lescan']
buffer (last 100 chars): b''
before (last 100 chars): b'Set scan parameters failed: Input/output error\r\n'
after: <class 'pexpect.exceptions.EOF'>
match: None
match_index: None
exitstatus: 1
flag_eof: True
pid: 8082
child_fd: 6
closed: False
timeout: 30
delimiter: <class 'pexpect.exceptions.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
searcher: searcher_re:
    0: re.compile("b'foooooo'")

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.5/dist-packages/pygatt/backends/gatttool/gatttool.py", line 294, in scan
    raise BLEError(message)
pygatt.exceptions.BLEError: Unexpected error when scanning

Windows 10 BGAPIBackend, Errors on char_write and char_read

I'm using pygatt with a BLED112 using python 3.6 on Windows 10. I'm using the development version from github, because the pypi version still has the termios issue.

I'm able to connect, scan, discover characteristics and receive data by subscribing to a readable characteristic.

When I try to char_write to a writable characteristic, I get Application error codes:

device.char_write('6e400004-b5a3-f393-e0a9-e50e24dcca9e', bytearray(b'test'))

When I try to char_read from a readable characteristic, I get Unable to read characteristic:

value = device.char_read('6e400003-b5a3-f393-e0a9-e50e24dcca9e')

I'm using the code from the example in the README with the logging and everything works except the above lines. Calling char_write_handle and char_read_handle directly with the appropriate handles fails as well.

I'm I doing something wrong?

pygatt.lescan() fails with TypeError: unhashable type: 'dict'

Python 2.7.3 (default, Mar 18 2014, 05:13:23)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pygatt import pygatt
>>> pygatt.lescan()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pygatt-0.0.1-py2.7.egg/pygatt/pygatt.py",
line 30, in lescan
    'name': match.group(3)
TypeError: unhashable type: 'dict'
>>>

hcitool output:

# hcitool lescan
LE Scan ...
D0:39:72:A1:B8:D0 (unknown)
D0:39:72:A1:B8:D0 Nexturn
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
90:59:AF:2A:C7:B8 (unknown)
90:59:AF:2A:C7:B8 Nexturn
D0:39:72:A1:B8:D0 (unknown)
D0:39:72:A1:B8:D0 Nexturn
90:59:AF:2A:C7:B8 (unknown)
90:59:AF:2A:C7:B8 Nexturn
D0:39:72:A1:B8:D0 (unknown)

BUG Connection not established

Gatttool is working (HCI Tool ver 5.43) and the following lines create a connection to my device:

gatttool -i hci0 -I
[   ][                 ][LE]> sec-level low
[   ][                 ][LE]> connect 00:1A:22:07:B2:D1 public
[CON][00:1A:22:07:B2:D1][LE]> 

But a very simple example using pygatt that incorporates the same commands does not work:

import pygatt
adapter = pygatt.GATTToolBackend()
adapter.start()
device = adapter.connect("00:1A:22:07:B2:D1")

A time out is raised. With (enhanced) debug output the traceback is:

DEBUG:pygatt.backends.gatttool.gatttool:gatttool_cmd=gatttool -i hci0 -I
INFO:pygatt.backends.gatttool.gatttool:Running...
INFO:pygatt.backends.gatttool.gatttool:Connecting to 00:1A:22:07:B2:D1 with timeout=5.0
DEBUG:pygatt.backends.gatttool.gatttool:gatttool_sendline=sec-level low
DEBUG:pygatt.backends.gatttool.gatttool:gatttool_sendline=connect 00:1A:22:07:B2:D1 public
ERROR:pygatt.backends.gatttool.gatttool:Timed out connecting to 00:1A:22:07:B2:D1 after 5.0 seconds.
Traceback (most recent call last):
  File "/home/pi/.homeassistant/hass/lib/python3.5/site-packages/pygatt/backends/gatttool/gatttool.py", line 322, in connect
    self.sendline(cmd)
  File "/usr/local/lib/python3.5/contextlib.py", line 66, in __exit__
    next(self.gen)
  File "/home/pi/.homeassistant/hass/lib/python3.5/site-packages/pygatt/backends/gatttool/gatttool.py", line 163, in event
    self.wait(event, timeout)
  File "/home/pi/.homeassistant/hass/lib/python3.5/site-packages/pygatt/backends/gatttool/gatttool.py", line 137, in wait
    raise NotificationTimeout()
pygatt.exceptions.NotificationTimeout: None

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "basic_bluez_gatttool_sample.py", line 11, in <module>
    device = adapter.connect("00:1A:22:07:B2:D1")
  File "/home/pi/.homeassistant/hass/lib/python3.5/site-packages/pygatt/backends/gatttool/gatttool.py", line 328, in connect
    raise NotConnectedError(message)
pygatt.exceptions.NotConnectedError: Timed out connecting to 00:1A:22:07:B2:D1 after 5.0 seconds.

I am surprised, what is going wrong? My guess is that the connection state parsing here is buggy, because newer gatttools do not print a connection successful.

AttributeError: 'str' object has no attribute 'name'

Hello,

i use a new Raspberry pi3 with the newest Version of Raspbian. I followed every instruction to install Bluez, Gatttool and pygatt. I have no Idea how to manage this Error. Please can you help me.
The Error is:

Traceback (most recent call last):
File "/home/pi/MIA/char_read.py", line 13, in
device = adapter.connect("D6:2C:B6:38:DF:24", address_type=ADDRESS_TYPE)
File "/usr/local/lib/python2.7/dist-packages/pygatt/backends/gatttool/gatttool.py", line 319, in connect
cmd = 'connect {0} {1}'.format(self._address, address_type.name)
AttributeError: 'str' object has no attribute 'name'

Thank you!

How to send authentication request to the BLE peripheral using the bgapi backend.

It appears to me that if the bgapi backend is used there is no means of initiating an authentication request, which is needed for a passkey based connection. Looking through bgapi.py, I can not see any function that supports this. For example, the connect function has no parameter for the password if the connection is encrypted.

Perhaps I am missing something?

BGAPI scan for devices fails because `len(field_value) / 16` cannot be interpreted as an integer

A user of a software I am writing is complaining of an occasional crash when he scans for Bluetooth devices.

He reports the crash only occurs occasionally on a macOS 10.12 computer. We are using pygatt 02197ff. I for myself have never experienced this issue on a Ubuntu 16.04 machine.

Traceback (most recent call last):
...
  devices = adapter.scan(timeout=1)
File "/usr/local/lib/python3.5/site-packages/pygatt/backends/bgapi/bgapi.py", line 317, in scan
  self.expect(ResponsePacketType.gap_end_procedure)
File "/usr/local/lib/python3.5/site-packages/pygatt/backends/bgapi/bgapi.py", line 517, in expect
  return self.expect_any([expected], *args, **kargs)
File "/usr/local/lib/python3.5/site-packages/pygatt/backends/bgapi/bgapi.py", line 565, in expect_any
  self._packet_handlers[packet_type](response)
File "/usr/local/lib/python3.5/site-packages/pygatt/backends/bgapi/bgapi.py", line 687, in _ble_evt_gap_scan_response
  name, data_dict = self._scan_rsp_data(args['data'])
File "/usr/local/lib/python3.5/site-packages/pygatt/backends/bgapi/bgapi.py", line 506, in _scan_rsp_data
  for i in range(0, len(field_value) / 16):  # 16 bytes
TypeError: 'float' object cannot be interpreted as an integer

I will try and collect more debug information (the data list received by BGAPIBackend._scan_rsp_data(self, data) and the content of field_value).

CPU Resources decrease after every connection try/timeout

Running pygatt on a Raspberry Pi B+ (Linux raspberrypi 4.1.13+ #826 PREEMPT Fri Nov 13 20:13:22 GMT 2015 armv6l GNU/Linux).
This piece of code

while True:
    # wait for scale to wake up and connect to it
    try:
        device = adapter.connect(ble_address, 5 , 'random')
        break
    except pygatt.exceptions.NotConnectedError:
        time.sleep( 5 )
        pass

starts using 2% CPU but this gradually builds to 98%. Connection Timeout of 5s increases, sleep time does not.

Tue, 09 Feb 2016 19:39:31 ERROR    connect Timed out connecting to f1:37:57:6c:dc:65 after 5 seconds.
Tue, 09 Feb 2016 19:39:36 INFO     connect Connecting with timeout=5
Tue, 09 Feb 2016 19:39:41 ERROR    connect Timed out connecting to f1:37:57:6c:dc:65 after 5 seconds.
Tue, 09 Feb 2016 19:39:46 INFO     connect Connecting with timeout=5

but after a while...

Tue, 09 Feb 2016 20:18:13 INFO     connect Connecting with timeout=5
Tue, 09 Feb 2016 20:18:54 ERROR    connect Timed out connecting to f1:37:57:6c:dc:65 after 5 seconds.
Tue, 09 Feb 2016 20:19:00 INFO     connect Connecting with timeout=5
Tue, 09 Feb 2016 20:19:42 ERROR    connect Timed out connecting to f1:37:57:6c:dc:65 after 5 seconds.
Tue, 09 Feb 2016 20:19:47 INFO     connect Connecting with timeout=5

The connection timeout has grown to 42 seconds.
It may not seem to be a great idea to try connecting over and over. In this particular case i need to connect to a bathroom scale which only wakes up for one minute after someone steps on it.
Any thoughts?

EDIT: increasing Connection timeout to 60 seconds will have this timeout increase to 76 seconds over one hour of operation.

immediate disconnect

I'm using pygatt (3.1.1) on my laptop and am connecting to
a Nordic SoC (nRF52832).

Frequently after establishing a connection (and a connection
is indicated on the Nordic radio I get a Disconnect event. Then the
pygatt connection request times out and throws an exception.

The debug output (and screen shot of wireshark session) are:

dev = adapter.connect(addr, address_type=ty)
INFO:pygatt.backends.gatttool.gatttool:Connecting to CD:EE:E4:3F:94:F6 with timeout=5.0
ERROR:pygatt.backends.gatttool.gatttool:Timed out connecting to CD:EE:E4:3F:94:F6 after 5.0 seconds.
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python2.7/dist-packages/pygatt-3.1.1-py2.7.egg/pygatt/backends/gatttool/gatttool.py", line 384, in connect
raise NotConnectedError(message)
pygatt.exceptions.NotConnectedError: Timed out connecting to CD:EE:E4:3F:94:F6 after 5.0 seconds.

disconnect

I can't get much diagnostics from the Nordic radio: Only connect/disconnect
event notifications.

This could very well be a Nordic issue and not pygatt: I don't have
any other BLE devices to test with.

Automatically chunk larger characteristic writes into 20 byte packets

Is it possible to write more than 20 bytes of data with a single char_write command? For some reason, when I try sending data that is greater than 20 bytes, the bgapi timesout. I know that 20 bytes is the limit for writing in one "chunk" of data for BLE, does the bgapi not automatically chop up the data into 20 byte chunks to send over, then send an "write execute" command? Thanks for any help!

Here's the logging and error I get:

`INFO:pygatt.backends.bgapi.bgapi:Characteristic 0x00002a19-0000-1000-8000-00805f9b34fb is handle 0x35
INFO:pygatt.backends.bgapi.bgapi:Characteristic descriptor 0x00002902-0000-1000-8000-00805f9b34fb is handle 0x36
INFO:pygatt.backends.bgapi.bgapi:Characteristic 0x00002a27-0000-1000-8000-00805f9b34fb is handle 0x3f
DEBUG:pygatt.device:Looking up handle for characteristic c4f51553-e1a4-cc97-2680-1b7d70348ffb
DEBUG:pygatt.device:Found
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<ResponsePacketType.attclient_attribute_write: 43>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a ResponsePacketType.attclient_attribute_write packet: Success
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<EventPacketType.attclient_procedure_completed: 17>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a EventPacketType.attclient_procedure_completed packet: Success
INFO:pygatt.device:Subscribed to uuid=c4f51553-e1a4-cc97-2680-1b7d70348ffb
DEBUG:pygatt.device:Looking up handle for characteristic c4f51553-e1a4-cc97-2680-1b7d70348ffb
DEBUG:pygatt.device:Found
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<ResponsePacketType.attclient_attribute_write: 43>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a ResponsePacketType.attclient_attribute_write packet: Success
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<EventPacketType.attclient_procedure_completed: 17>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a EventPacketType.attclient_procedure_completed packet: Success
INFO:pygatt.device:Received notification on handle=0x2b, value=0xb'51000000'
43
bytearray(b'Q\x00\x00\x00')
DEBUG:pygatt.device:Looking up handle for characteristic c4f51553-e1a4-cc97-2680-1b7d70348ffb
DEBUG:pygatt.device:Found
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<ResponsePacketType.attclient_attribute_write: 43>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a EventPacketType.attclient_attribute_value packet: Success
DEBUG:pygatt.backends.bgapi.bgapi:attribute handle = 2b
DEBUG:pygatt.backends.bgapi.bgapi:attribute type = 1
DEBUG:pygatt.backends.bgapi.bgapi:attribute value = 0xb'51000000'
DEBUG:pygatt.backends.bgapi.bgapi:Received a ResponsePacketType.attclient_attribute_write packet: Success
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<EventPacketType.attclient_procedure_completed: 17>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a EventPacketType.attclient_procedure_completed packet: Success
DEBUG:pygatt.device:Looking up handle for characteristic c4f51551-e1a4-cc97-2680-1b7d70348ffb
DEBUG:pygatt.device:Found
INFO:pygatt.device:Received notification on handle=0x2b, value=0xb'53000100'
DEBUG:pygatt.backends.bgapi.bgapi:Expecting a response of one of [<ResponsePacketType.attclient_attribute_write: 43>] within 1.000000s
DEBUG:pygatt.backends.bgapi.bgapi:Received a EventPacketType.attclient_attribute_value packet: Success
DEBUG:pygatt.backends.bgapi.bgapi:attribute handle = 2b
DEBUG:pygatt.backends.bgapi.bgapi:attribute type = 1
DEBUG:pygatt.backends.bgapi.bgapi:attribute value = 0xb'53000100'
43
bytearray(b'S\x00\x01\x00')
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\threading.py", line 914, in _bootstrap_inner
self.run()
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\site-packages\pygatt\backends\bgapi\bgapi.py", line 583, in _receive
packet_type, args = self._lib.decode_packet(packet)
TypeError: 'NoneType' object is not iterable

Traceback (most recent call last):
File "C:/Users/user/Documents/BLE app test/testcode.py", line 47, in
device.char_write(proto_data_uuid, data)
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\site-packages\pygatt\device.py", line 93, in char_write
wait_for_response=wait_for_response)
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\site-packages\pygatt\backends\bgapi\device.py", line 21, in wrapper
return func(self, *args, **kwargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\site-packages\pygatt\backends\bgapi\device.py", line 114, in char_write_handle
self._backend.expect(ResponsePacketType.attclient_attribute_write)
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\site-packages\pygatt\backends\bgapi\bgapi.py", line 521, in expect
return self.expect_any([expected], *args, **kargs)
File "C:\Users\user\AppData\Local\Programs\Python\Python35\lib\site-packages\pygatt\backends\bgapi\bgapi.py", line 557, in expect_any
raise exc
pygatt.backends.bgapi.exceptions.ExpectedResponseTimeout: Timed out after 1.000000s waiting for [<ResponsePacketType.attclient_attribute_write: 43>]`

autoreconnect in @connection_required decorator

Would it make sense to automatically reconnect when using the decorated methods (char_read, char_write, ...)

In an interactive environment where the user is triggering the reads/writes it is easy for the device to timeout (I would have to increase the timeout to minutes, which is too long), which means the user has to reconnect every time a read/write returns timeout and then retry the read/write.

Is there a better way to go about this? Or should I establish a brand new connection for each read/write?

Thanks!

VersionConflict with nose on install

Hello,

When i try to install your script, I get this error :
pkg_resources.VersionConflict: (nose 1.3.7 (/usr/local/lib/python2.7/dist-packages), Requirement.parse('nose==1.3.1'))
Can you change your requirement ?

gatttool high CPU usage on 'disconnect' command

Hi,
This is not exactly a pygatt issue, but I just wanted to get some inputs. Doing a gatttool disconnect causes CPU usage of 70-80% till gatttool is killed. I am using bluez 5.37. I also notice this issue has been noted as a TODO in gatttool.py. So has anyone had a go at trying to resolve this?

Thanks

pexpect.TIMEOUT: Timeout exceeded

I am trying to connect to an nRF8001 using pygatt. I am able to connect to it using gatttool but am facing some issues while using pygatt. My code is as follows

import binascii
import pygatt
import logging

logging.basicConfig()
logging.getLogger('pygatt').setLevel(logging.DEBUG)

FRONT_MODULE_ADDRESS = "E7:48:F5:CD:DF:D3"
ADDRESS_TYPE = pygatt.BLEAddressType.public

adapter = pygatt.GATTToolBackend();
adapter.start()
device = adapter.connect(FRONT_MODULE_ADDRESS)

adapter.stop()

I do appear to connect to the peripheral as an LED lights up on it but I get a timeout error from pexpect.

Traceback (most recent call last):
  File "ble.py", line 13, in <module>
    adapter.start()
  File "/usr/local/lib/python2.7/dist-packages/pygatt/backends/gatttool/gatttool.py", line 224, in start
    self._con.expect(r'\[LE\]>', timeout=1)

  File "/usr/lib/python2.7/dist-packages/pexpect/__init__.py", line 1418, in expect
    timeout, searchwindowsize)
  File "/usr/lib/python2.7/dist-packages/pexpect/__init__.py", line 1433, in expect_list
    timeout, searchwindowsize)
  File "/usr/lib/python2.7/dist-packages/pexpect/__init__.py", line 1535, in expect_loop
    raise TIMEOUT(str(err) + '\n' + str(self))
pexpect.TIMEOUT: Timeout exceeded.
<pexpect.spawn object at 0xb666fe10>
version: 3.2
command: /usr/bin/gatttool
args: ['/usr/bin/gatttool', '-i', 'hci0', '-I']
searcher: <pexpect.searcher_re object at 0xb666fe50>
buffer (last 100 chars): ''
before (last 100 chars): ''
after: <class 'pexpect.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 26041
child_fd: 3
closed: False
timeout: 30
delimiter: <class 'pexpect.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1

I am not really sure if I am doing anything wrong.

Windows7 BGAPIBackend, ValueError: Cannot configure port.

I have installed pygatt and the driver for my BLED112-v1 USB dongle from Bluegiga. The driver is Bluegiga 5.1.2600.0. The device shows up in the device manager as Bluegiga Bluetooth Low Energy (COM29). It's settings are configured by default to

  • 9600bps
  • 8 data bits
  • 1 stop bit

If I do the following:
import pygatt
adapter = pygatt.BGAPIBackend(serial_port='COM29') #without serial_port specified, an error is thrown
adapter.start()

The following error occurs:
ValueError: Cannot configure port, some setting was wrong. Original message: WindowsError(2, 'The system cannot find the file specified.') Changing the baud rate to 115200 doesn't seem to change things.

What could the problem be?

Subscribe raises a ExpectedResponseTimeout even though receiving notifications

A ExpectedResponseTimeout exception is being thrown when conducting the following test:

  1. Connect to a BLE device (using the BGAPI backend)
  2. Subscribe to a characteristic
  3. Subscribe to a second characteristic

Step 3 raises a ExpectedResponseTimeout even though I am correctly receiving notifications from this second characteristic.

Minimum not working example:

import pygatt
import time

def callback_func(handle, data):
    print(handle)

adapter = pygatt.BGAPIBackend()
try:
    adapter.start()
    device = adapter.connect('A0:E6:F8:75:49:05')
    for index in range(2):
        print('---------- {} ----------'.format(index))
        uuid = pygatt.util.uuid16_to_uuid(0xBF01 + index)
        device.subscribe(uuid, callback=callback_func)
    time.sleep(10)
finally:
    adapter.stop()

Output:

---------- 0 ----------
---------- 1 ----------
30
30
30
30
34
30
34
...
30
34

---------------------------------------------------------------------------
ExpectedResponseTimeout                   Traceback (most recent call last)
<ipython-input-4-aa24e1013855> in <module>()
     15         print('---------- {} ----------'.format(index))
     16         uuid = pygatt.util.uuid16_to_uuid(0xBF01 + index)
---> 17         device.subscribe(uuid, callback=callback_func)
     18     time.sleep(10)
     19 finally:

/usr/local/lib/python3.5/dist-packages/pygatt/device.py in subscribe(self, uuid, callback, indication)
    158                     characteristic_config_handle,
    159                     properties,
--> 160                     wait_for_response=False
    161                 )
    162                 log.info("Subscribed to uuid=%s", uuid)

/usr/local/lib/python3.5/dist-packages/pygatt/backends/bgapi/device.py in wrapper(self, *args, **kwargs)
     19         if self._handle is None:
     20             raise exceptions.NotConnectedError()
---> 21         return func(self, *args, **kwargs)
     22     return wrapper
     23 

/usr/local/lib/python3.5/dist-packages/pygatt/backends/bgapi/device.py in char_write_handle(self, char_handle, value, wait_for_response)
    104                     self._handle, char_handle, value_list))
    105 
--> 106             self._backend.expect(ResponsePacketType.attclient_attribute_write)
    107             packet_type, response = self._backend.expect(
    108                 EventPacketType.attclient_procedure_completed)

/usr/local/lib/python3.5/dist-packages/pygatt/backends/bgapi/bgapi.py in expect(self, expected, *args, **kargs)
    515 
    516     def expect(self, expected, *args, **kargs):
--> 517         return self.expect_any([expected], *args, **kargs)
    518 
    519     def expect_any(self, expected_packet_choices, timeout=None,

/usr/local/lib/python3.5/dist-packages/pygatt/backends/bgapi/bgapi.py in expect_any(self, expected_packet_choices, timeout, assert_return_success)
    551                             expected_packet_choices, timeout)
    552                         exc.__cause__ = None
--> 553                         raise exc
    554                     continue
    555 

ExpectedResponseTimeout: Timed out after 1.000000s waiting for [<ResponsePacketType.attclient_attribute_write: 43>]

Is this error normal? When trying to read the subscribe code I see in line 160: wait_for_response=False which I assumed means we are not waiting for a response.

Trying to use pygatt on RPi (Jessie)

Trying to use Pygatt on a Raspberry Pi with latest Rapbian Jessie installed.
Bluez installed Version: 5.23-2+b1
gatttool works and is able to connect to BLE device
latest pexpect installed and working

The script: (with correct address)

# pygatt test
import pygatt.backends

adapter = pygatt.backends.GATTToolBackend()
device = adapter.connect('f1:37:57:XX:XX:XX')
value = device.char_read("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b")

returns

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    device = adapter.connect('f1:37:57:XX:XX:XX')
  File "/home/pi/Pygatt-master/pygatt/backends/gatttool/gatttool.py", line 178, in connect
    self._con.sendline('sec-level low')
AttributeError: 'NoneType' object has no attribute 'sendline'

Any pointers where to start looking?
/paul

Writing to handle

Hi, i tried everyhting i could but i cant get device.char_write_handle() to work.
im trying to write to handle 0x0025 the value ff000000, i havent been able to find any propper documentation on how to use this function so i cant seem to get it to work
@peplin

Writing to Descriptor

I just came over pygatt while trying to connect to a cheap Pulse Oximeter (BerryMed). This one requires to write to the Client Character Config Descriptor to enable the streaming of data packets.

Since the CCCD is not included during characteristics discovery, pygatt doesn't let me write to it using its UUID. Any suggestions how I can write to this descriptor using pygatt?

EDIT: It looks like some work on this has been done on the branch "gattool-fix"!?

pygatt.lescan() "disables" interface after scan.

Every time i use lescan() i must reset the interface to do another scan:

>>> pygatt.lescan()
[{'name': 'Nexturn', 'address': 'D0:39:72:A1:D2:58'}, {'name': 'Nexturn', 'address': '90:59:AF:2A:C7:B8'}, {'name': 'Nexturn', 'address': 'D0:39:72:A1:B8:D0'}]

>>> pygatt.lescan()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pygatt-0.0.1-py2.7.egg/pygatt/pygatt.py", line 22, in lescan
    scan.expect("foooooo", timeout=timeout)
  File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1316, in expect
    return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
  File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1330, in expect_list
    return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
  File "/usr/lib/python2.7/dist-packages/pexpect.py", line 1401, in expect_loop
    raise EOF (str(e) + '\n' + str(self))
pexpect.EOF: End Of File (EOF) in read_nonblocking(). Exception style platform.
<pexpect.spawn object at 0xb68bdbf0>
version: 2.4 ($Revision: 516 $)
command: /usr/bin/sudo
args: ['/usr/bin/sudo', 'hcitool', 'lescan']
searcher: searcher_re:
    0: re.compile("foooooo")
buffer (last 100 chars):
before (last 100 chars): Set scan parameters failed: Input/output error
after: <class 'pexpect.EOF'>
match: None
match_index: None
exitstatus: None
flag_eof: True
pid: 757
child_fd: 3
closed: False
timeout: 30
delimiter: <class 'pexpect.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1

>>> pygatt.reset_bluetooth_controller()
Re-initializing Bluetooth controller

>>> pygatt.lescan()
[{'name': 'Nexturn', 'address': 'D0:39:72:A1:D2:58'}, {'name': 'Nexturn', 'address': '90:59:AF:2A:C7:B8'}, {'name': 'Nexturn', 'address': 'D0:39:72:A1:B8:D0'}]
>>>

hcitool works on command line with muliple scans:

# hcitool lescan
LE Scan ...
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
D0:39:72:A1:B8:D0 (unknown)
90:59:AF:2A:C7:B8 (unknown)
90:59:AF:2A:C7:B8 Nexturn
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
[CTTL+C]

# hcitool lescan
LE Scan ...
D0:39:72:A1:D2:58 (unknown)
D0:39:72:A1:D2:58 Nexturn
D0:39:72:A1:B8:D0 (unknown)
D0:39:72:A1:B8:D0 Nexturn

Possiblity to recconect on disconnect

When the Bluetooth device disconnects the script terminates, is it possible when a write fails due to disconnect that it automatically tries to connect again ?

what kind of fitband

Hi
I want to start work with pygatt, looks very promising. and I want to buy a fit band, could you please tell me with what model of fit band did you test it and was successful?
Thanks.

No BGAPI compatible device detected on Ubuntu16.04

Hello,
I'm now using a BLED112 on my Ubuntu 16.04. As the instruction said, Linux should automatically recognize the device. However, I got the following errors:

>>> adapter = pygatt.BGAPIBackend()
>>> adapter.start()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pygatt/backends/bgapi/bgapi.py", line 178, in start
    self._open_serial_port()
  File "/usr/local/lib/python2.7/dist-packages/pygatt/backends/bgapi/bgapi.py", line 163, in _open_serial_port
    "No BGAPI compatible device detected")
pygatt.exceptions.NotConnectedError: No BGAPI compatible device detected

Should I specify the serial port? If so, how could I know which port the device is using?

Thanks

Windows 7 error in reset() in gatttool.py

I'm using the development version of pygatt from github. When running the example code in basic_bluez_gatttool_sample.py, there is an error when adapter.start() is called. I have traced this to the following line in gatttool.py. The offending line is:
subprocess.Popen(["sudo", "systemctl", "restart", "bluetooth"]).wait()

Clearly this command is not supported on Windows.

Not able to subscribe to characteristic.

I am not able to subscribe to a characteristic. I can successfully scan, connect, discover_characteristics & read, but it won't let me subscribe.

import pygatt
import logging
#logging.basicConfig()
#logging.getLogger('pygatt').setLevel(logging.DEBUG)
 
adapter = pygatt.BGAPIBackend()

def print_this(h, stuff):
    print(stuff)
 
adapter.start()
devices = adapter.scan()
for device in devices:
    if "custom_device" in device["name"].lower():
        print("found device")
        break
    
device = adapter.connect(device["address"])
chars = device.discover_characteristics() # I get some type of a warning here. "UUID b'ffe1' is of unknown type"
value = device.char_read("00002a05-0000-1000-8000-00805f9b34fb") #this address was found by printing the `chars` array
device.subscribe('00002a05-0000-1000-8000-00805f9b34fb', print_this) #ExpectedResponseTimeout

The last line throws an ExpectedResponseTimeout: Timed out after 1.0000s waiting for [<EventPacketType.attclient_procedure_completed: 17>].

However, if I print out device._callbacks I can see my callback was added to the set.
defaultdict(<class 'set'>, {14: {<function print_this at 0x0000020B64F9318>}})

If I turn on logging then I can see that data is coming in, but it's not calling the print_this callback.

INFO:pygatt.device:Received notification on handle=0x12, value=0xb'430002800b1ff1e00d6fff0f7cfff'
INFO:pygatt.device:Received notification on handle=0x12, value=0xb'410003500a1ff1d00c6eff0a2b437'

I tried this which worked as expected:

value = "Hello World"
handle = 14
with device._lock:
    if handle in device._callbacks:
        for callback in device._callbacks[handle]:
            callback(handle, value)

>> Hello World

So I am pretty baffled at this point. Any help you can give me would be hugely appreciated.

Unable to auto-detect BLED112

Hi,
Since last update, auto-detect of a BLED112 fails.
After some investigations, it seems that the error is caused by the reboot of the serial port. Seems like the BLED112 doesn't have enough time to give full informations to the auto-detect.

INFO:pygatt.backends.bgapi.bgapi:Initialized new BGAPI backend on None
INFO:pygatt.backends.bgapi.bgapi:Auto-discovering serial port for BLED112
INFO:pygatt.backends.bgapi.util:Found 1 serial USB devices
DEBUG:pygatt.backends.bgapi.util:Checking serial USB device: /dev/ttyACM0 - Low Energy Dongle - CDC control
DEBUG:pygatt.backends.bgapi.util:USB device: Low Energy Dongle - CDC control VID=0x2458 PID=0x0001 on /dev/ttyACM0
DEBUG:pygatt.backends.bgapi.bgapi:Attempting to connect to serial port after restarting device
INFO:pygatt.backends.bgapi.bgapi:Auto-discovering serial port for BLED112
INFO:pygatt.backends.bgapi.util:Found 1 serial USB devices
DEBUG:pygatt.backends.bgapi.util:Checking serial USB device: /dev/ttyACM0 - n/a
Unable to auto-detect BLED112 serial port

I'm on Ubuntu 16.04, never had this problem before last update.

Unable to start BLED112 dongle using adapter.start()

Hi,

I have used the BLED112 dongle on a different PC and didn't face this issue but I needed to set up a new computer with pygatt and ran into issues. I was trying to execute the following code which has worked for me in the past but for some reason the following code kept giving me an error:

import pygatt

adapter = pygatt.BGAPIBackend(serial_port = "COM4")
print adapter._serial_port
try:
    adapter.start()
    devices = adapter.scan()
    print devices
    device = adapter.connect('88:6b:0f:2f:65:d6')
    print device
    value = device.char_read("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b")
except:
    print "Failed"
finally:
    adapter.stop()
Traceback (most recent call last):
  File "D:\App1.py", line 18, in <module>
    adapter.stop()
  File "C:\Python27\lib\site-packages\pygatt\backends\bgapi\bgapi.py", line 218, in stop
    if self._running.is_set():
AttributeError: 'NoneType' object has no attribute 'is_set'

I had confirmed that the COM port number was correct before running my code but it looked like the script could never find the port. Looking at issue #118 I saw that the author had success by modifying bgapi.py by adding a delay in the adapter.start() function. Since I was not having much luck I decided to try this out as well and found that by adding a 1 second delay before self._open_serial_port() fixed my issue.

    self.send_command(CommandBuilder.system_reset(0))
    self._ser.flush()
    self._ser.close()
    **time.sleep(1)**
    self._open_serial_port()
    self._receiver = threading.Thread(target=self._receive)
    self._receiver.daemon = True

While this is currently working for me, I would like to know if this is a common issue for people using Windows 10 and/or using the BLED112 with a USB 3.0 port.

GATTToolBackend returns incorrect device names

On an Ubuntu 16.04 computer with bluez 5.43, GATTToolBackend returns incorrect device names when scanning:

Debug output when adding the following line after line 300 in backends/gatttools/gatttools.py: print(line)

LE Scan ...
7F:6C:9D:31:F1:DC (unknown)
INFO:pygatt.backends.gatttool.gatttool:Discovered 7F:6C:9D:31:F1:DC (None)
A0:E6:F8:75:50:84 BF PPG Project
INFO:pygatt.backends.gatttool.gatttool:Discovered A0:E6:F8:75:50:84 (BF)

In this example BF PPG Project is incorrectly identified as BF. This is a result of name being by matched by the regular expression \(?[\w]+\)?.

However, the Bluetooth spec does not impose the name to be one word, nor to be only alpha-numeric characters:

Section 12.1:

The Device Name characteristic shall contain the name of the device as an UTF-8 string as defined in Section 3.2.2. [...] The Device Name characteristic value shall be 0 to 248 octets in length. A device shall have only one instance of the Device Name characteristic.

\(?[\w]+\)? should be changed to \(?.+\)?

gatttool is deprecated

I'm having a hard time finding any official notification, but it looks like hcitool and gatttool are being deprecated by BlueZ. The latest package installed in Arch doesn't include it, and you have to install bluez-utils-compat from the AUR.

Ideally, pygatt can move away from shelling out the CLI tool so this doesn't matter - e.g. the work in progress in #95.

I'm creating this issue for awareness in case anyone else is on bleeding edge distro and finds these tools are suddenly missing.

char_write_handle() bogged down by lock

Symptom connection.char_write_handle() takes a very long time process with a lot of the time spent waiting for lock. The longer application is running (and more commands are sent) the worse the issue seems to get. When notifications are enabled and are received at a rate of 20-50 per second, connection.char_write_handle() becomes practically impossible to use (can take several seconds for it to be sent, if at all.).

Removing lock during char_write_handle() resolves the issue. But its not clear to me what the purpose of this lock is and what other issues this hack creates.

If anyone's familiar with this code I'd appreciate some feedback.

Windows error due to use of pexpect in gatttool.py

I'm using the development version of pygatt. In in the function start() on line 245 of gattyool.py, pexpect is used to run a command as follows:
self._con = pexpect.spawn(gatttool_cmd, logfile=self._gatttool_logfile)

pexpect does not work well on Windows systems although there is wexpect. See: the pexpect doc
It would be good to have a cross platform solution.

NotificationTimeout exception and NotConnectedError while trying to read battery value of sensor.

Hey..
I am trying to connect to a BLE device from a raspberry pi and using pygatt for connecting, reading and writing values from and to sensor to get notifications. Most of the times I get what I want but some times I receive NotificationTimeout and NotConnectedError(even though the device is connected).
I am receiving these errors while trying to read the battery value of a bluetooth sensor using char_read function. Also, these errors are sporadic and I can not pin point when it is going to happen. Any help is appreciated. Thank you.

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.