Code Monkey home page Code Monkey logo

bluepy's Introduction

bluepy

Python interface to Bluetooth LE on Linux

This is a project to provide an API to allow access to Bluetooth Low Energy devices from Python. At present it runs on Linux only; I've mostly developed it using a Raspberry Pi, but it will also run on x86 Debian Linux.

The code is tested on Python 2.7 and 3.4; it should also work on 3.3.

There is also code which uses this to talk to a TI SensorTag (www.ti.com/sensortag).

An example to interface the Nordic Semiconductor ASA IoT Sensor Kit, Thingy:52 is available in thingy52.py (https://www.nordicsemi.com/eng/Products/Nordic-Thingy-52).

Installation

The code needs an executable bluepy-helper to be compiled from C source. This is done automatically if you use the recommended pip installation method (see below). Otherwise, you can rebuild it using the Makefile in the bluepy directory.

To install the current released version, on most Debian-based systems:

$ sudo apt-get install python-pip libglib2.0-dev
$ sudo pip install bluepy

On Fedora do:

$ sudo dnf install python-pip glib2-devel

For Python 3, you may need to use pip3:

$ sudo apt-get install python3-pip libglib2.0-dev
$ sudo pip3 install bluepy

If this fails you should install from source.

$ sudo apt-get install git build-essential libglib2.0-dev
$ git clone https://github.com/IanHarvey/bluepy.git
$ cd bluepy
$ python setup.py build
$ sudo python setup.py install

I would recommend having command-line tools from BlueZ available for debugging. There are instructions for building BlueZ on the Raspberry Pi at http://www.elinux.org/RPi_Bluetooth_LE.

Documentation

Documentation can be built from the sources in the docs/ directory using Sphinx.

An online version of this is currently available at: http://ianharvey.github.io/bluepy-doc/

License

This project uses code from the bluez project, which is available under the Version 2 of the GNU Public License.

The Python files are released into the public domain by their author, Ian Harvey.

Release Notes

Release 1.3.0

  • New getState() method for Peripheral class
  • New exception structure / error reporting (#311, #317, #326) BTLEException now has subclasses BLTEDisconnectError, BTLEManagementError, etc. which report an error code and error message passed up from the lower layers, where appropriate.
  • Partial merge #311: aids to debugging; bluepy-helper reports version; fix crash
  • Partial merge #311 and #302: pair() and unpair() now supported
  • Fix #169: 0-byte characteristic writes are now supported
  • Merge #302: OOB data now supported
  • Merge #312: better comments on sample code in docs, better scanner example
  • Fix #292: Unicode string decoding errors in scan data
  • Merge #308: don't ignore sensitivity option during discovery
  • Merge #301: fix Peripheral documentation
  • Fix #286: return list of services from Scan entry

Release 1.2.0

  • Merge #245: Update underlying Bluez version to 5.47
  • Merge #284: Readme updated with Fedora install instructions
  • Merge #283: Fixes for passive scan interruption
  • Merge #275, fix #259: non-ASCII device names now don't break decoding
  • Fix #263, #278: return UUID in scan results
  • Merge #262: Return correct address type in passive scan

Release 1.1.4:

  • Further attempts to fix #158. setup.py rewritten.

There was no release 1.1.3 made

Release 1.1.2: now deleted

  • Re #158: Try to make PyPI installation more robust
  • Merge #214: add passive scan support
  • Merge #213: Add Thingy:52 support

Release 1.1.1

  • Workaround #200: remove -Werror from Makefile
  • Fix #191: generate BTLEException not ValueError, if helper is killed
  • Fix #189: error calling getCharacteristics() when Service has no characteristics
  • Workaround #192: Use make -j1 explicitly

Release 1.1.0

  • Merge #180: Peripheral.connect() can now take ScanEntry object (like constructor)
  • Merge #162: Add build_ext builder to setup.py
  • Merge #166: Fix crash in getServiceByUUID()
  • Fix #148: Add UUIDs for declarations (e.g. 0x2800 = Primary Service Declaration)
  • Fix #28: Sensortag accelerometer values now scaled properly
  • Merge #89: Add support for descriptors
  • Fix #157: make 'services' a property
  • Fix #111: make parameter names match documentation
  • Fix #128: Characteristic.write() was missing a return value
  • Read battery level on Sensortag
  • Formatting/style fixes (#170 and others)

Release 1.0.5

  • Fix issue #123: Scanner documentation updated
  • Fix #125: setup.py error reporting on Python 3 if compilation fails
  • Fix for issue #127: setup.py fails to rebuild bluepy-helper

Release 1.0.4

  • Scanner now available as bluepy.blescan module and 'blescan' command
  • Fix example scanner code in documentation
  • Python 3 installation fixes
  • Fix issues #69, #112, #115, #119

Release 1.0.3

  • Now available on PyPI as bluepy. Installs via pip.

Release 0.9.12

  • Support for CC2650 sensortag
  • Documentation fixes
  • Bug fix: DefaultDelegate has a handleDiscovery method
  • Bug fix: keypress now works with both V1.4 and V1.5 firmware

Release 0.9.11

  • Minor consistency improvements & bug fixes
  • Scanner now has getDevices() call
  • Docs updated

Release 0.9.10

  • Now with Scan functionality

Release 0.9.9

  • Now based on Bluez r5.29
  • UUIDs held in separate JSON file, script added to update from Web
  • Added setup.py and init.py for use with setuptools
  • Allows indications as well as notifications
  • Bug fixes (see pull requests #46, #48, #35)

Release 0.9.0

  • Support for Notifications
  • SensorTag code now supports keypress service
  • Bug fix for SetSecurityLevel
  • Support for Random address type
  • More characteristic and service UUIDs added

Release 0.2.0

  • Sphinx-based documentation
  • SensorTag optimisations
  • Improved command line interface to sensortag.py
  • Added .gitignore file (github issue #17)

Release 0.1.0

  • this has received limited testing and bug fixes on Python 3.4.1
  • fix for exceptions thrown if peripheral sends notifications

Release dated 2-Jul-2014

  • expand AssignedNumbers class definitions
  • add getCommonName() to UUID type, returns human-friendly string

Release dated 14-Apr-2014:

  • make btle.py useful from the command line
  • add AssignedNumbers class

Release dated 12-Mar-2014

  • add exceptions, and clean up better on failure

Initial release 19-Oct-2013:

TO DO list

The following are still missing from the current release:

  • Unit test
  • Peripheral role support

bluepy's People

Contributors

adminq80 avatar agordon avatar balloob avatar basil-huber avatar beluga3858 avatar briarfox avatar csonsino avatar devanlai avatar gandy92 avatar ge0rg avatar gield avatar iamalazybum avatar ianharvey avatar kalfa avatar louiscaron avatar lucdachary avatar markrages avatar michaelpetrov avatar mickiebyrd avatar mikimer avatar omer-qadir avatar peterkersch avatar przemof avatar rmanders avatar ronnymajani avatar sm-fifteen avatar stephstcom avatar thorsten-sick avatar tpoliaw avatar tribela 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  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

bluepy's Issues

gatttool -t

Hi Ian,

Not so much an issue as a request.

I'd need to add the -t address type [public|random] to the gatttool I believe during the connect. I specifically need random and could simply hard code it, but... Having the flag and option would be better your tool over time.

Rather than trial-and-error it, wasting an hour or two, might you suggest where it would be best added?

Thanks!

Jeff

Error in writing a characteristic

Hi,

Trying write a characteristic appears the following error :

Unhandled exception in thread started by <function peticion_datos_PTHVcc at 0xb6adc830>
Traceback (most recent call last):
File "duracion_bateria.py", line 218, in peticion_datos_PTHVcc
carac_comando.write("58".decode("hex"), True)
File "/home/pi/python/btle.py", line 142, in write
self.peripheral.writeCharacteristic(self.valHandle, val, withResponse)
No se encuentra el dispositivo BLE
File "/home/pi/python/btle.py", line 377, in writeCharacteristic
return self._getResp('wr')
File "/home/pi/python/btle.py", line 262, in _getResp
resp = Peripheral.parseResp(rv)
File "/home/pi/python/btle.py", line 227, in parseResp
(tag, tval) = item.split('=')
ValueError: need more than 1 value to unpack

Could someone tell me what I am doing bad ?

Thanks and regards.

random address not working

I am using bluepy on Debian (on the Intel Edison i386 board). While there is no problem connecting to BLE devices that expose a 'public' address (it works just fine with the TI SensorTag and with the RedBearLab BLE Mini), there is a problem (main.BTLEException: Failed to connect to peripheral) connecting to devices that expose a 'random' address (e.g. the RedBearLab BLE Blend Micro).
Please note that 'gatttool -b xx:xx:xx:xx:xx:xx -I' connects to a device with 'public' address and 'gatttool -b xx:xx:xx:xx:xx:xx -I -t random' to a device with 'random' address.

Indications?

Are indications supported yet? They're very similar, and notifications are working fine for me, but indications aren't appearing at all.

btle.py doesnt work after reboot

I've installed bluez 5.30 (downloaded and built manually).
Then clone and build bluepy.
Then I ran python btle.py XX:YY:...... and it worked perfectly.

However after the first restart is doesnt work anymore.

Connecting to: C4:BE:84:76:F3:14, address type: public
Traceback (most recent call last):
File "btle.py", line 481, in
conn = Peripheral(devAddr, addrType)
File "btle.py", line 193, in init
self.connect(deviceAddr, addrType)
File "btle.py", line 321, in connect
rsp = self._getResp('stat')
File "btle.py", line 278, in _getResp
resp = Peripheral.parseResp(rv)
File "btle.py", line 241, in parseResp
(tag, tval) = item.split('=')
ValueError: need more than 1 value to unpack
Exception ValueError: 'need more than 1 value to unpack' in <bound method Peripheral.del of <main.Peripheral instance at 0x76aef4e0>> ignored

HeartRate notify

Hi there, first of all thanks for reading this!

Currently i am working on a heart rate monitor in python with the polar H7 and i'm getting stuck with the notify part of BLE heart rate.

import struct
import btle


class MyDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)

    def handleNotification(self, cHandle, data):
        print(data)


if __name__ == '__main__':
    heartrate_uuid = btle.UUID(0x2a38)

p = btle.Peripheral("00:22:D0:2B:F8:EC")
p.setDelegate(MyDelegate())

print("Connected")

try:
    print("Setting Characteristics")
    ch = p.getCharacteristics(uuid=heartrate_uuid)[0]
    print("Setting Done, writing now")
    ch.write(struct.pack('<bb', 0x01, 0x00))
    print("writing Done, looping now")
    while True:
        if p.waitForNotifications(1.0):
            print("Notification trigger")
            continue
    print("Waiting")
finally:
    p.disconnect()

Im not sure where i go wrong but i guess i dont have the right setup_data (from the example)

Can someone get me back on the right track?

btle.py w/ python3.4 hangs after helper greetings

See #5 (comment)
reported by @BrianAtLonmed

Shortly:

pi@raspberrypi ~ $ python3 work/bluepy/bluepy/bluepy/btle.py e0:c7:9d:5e:4a:9c
Connecting to: e0:c7:9d:5e:4a:9c
Running /home/pi/work/bluepy/bluepy/bluepy/bluepy-helper
Sent: conn e0:c7:9d:5e:4a:9c

Got: '# bluepy-helper.c built at 13:33:00 on Sep 4 2014\n'
and then it does not read anything further.

Expected behaviour, send a conn command to the specified address.

Humidity Sensor

Uses the humidity sensor scaling for the older sensorTag instead of scaling for HTC1000 used in newer CC2650 sensorTag. Could keep track of which sensorTag is in use and use the appropriate scaling.

SHT21 (old sensorTag)
humidity =-6+125_raw/65536
temperature =-4686 + 175.72_raw/65536

HDC1000 (CC2650 sensorTag)
humidity = (raw/65536)_100
temperature = (raw/65536)_165 - 40

Note: at least one of these values should also have some status bits masked off and attention should be paid to data types and rounding.

Unable to access Accelerometer data from CC2650_SensorTag

I tried to read the Temperature data from the Sensor tag and I was able to do it. But reading accelerometer data throws error. This is the command I executed:

pi@raspberrypi ~/bluepy/bluepy $ sudo python sensortag.py 68:C9:0B:06:64:84 -n 5 -A

Which returned the following:

Connecting to 68:C9:0B:06:64:84
Traceback (most recent call last):
  File "sensortag.py", line 293, in <module>
    main()
  File "sensortag.py", line 257, in main
    tag.accelerometer.enable()
  File "sensortag.py", line 21, in enable
    self.service = self.periph.getServiceByUUID(self.svcUUID)
  File "/home/pi/bluepy/bluepy/btle.py", line 365, in getServiceByUUID
    svc = Service(self, uuid, rsp['hstart'][0], rsp['hend'][0])
KeyError: 'hstart'

connection is not within python

Can't setting up the address & connection be done within the program? In other words, can't establishing the initial connection be done in Python? Typing in manual commands goes against just simply powering up & running the app.

Support for Sensortag 2

TI has a new Sensortag 2, about the same shape and size as the original Sensortag but with a couple more sensors, a new processor, and better battery life.

When I try to connect to it with sensortag.py I get this:

emv@rubus ~/bluepy/bluepy $ python ./sensortag.py --all 68:C9:0B:06:C9:08
Connecting to 68:C9:0B:06:C9:08
Traceback (most recent call last):
  File "./sensortag.py", line 255, in <module>
    tag.barometer.enable()
  File "./sensortag.py", line 128, in enable
    self.calChr = self.service.getCharacteristics(self.calUUID) [0]
IndexError: list index out of range

There's been some porting work to support the Sensortag 2 from node.js, and there's UUIDs and sample code etc pointed to from here:

sandeepmistry/node-sensortag#34

which should be a useful stop to sort through what has changed.

How to force pairing with a device with Bluepy?

Hello,
I have successfully established an LE connection to my BLE device with Bluepy. Now for testing reasons, I would like to control the authentication and encryption of the link. Is this possible? I have tried setting the security level but it did not change anything. Is is possible to do this? If this is the case, who controls the storage of the link keys?
Thanks

Works great until I try to use the write() method

I've had success using bluepy to connect to and read characteristics from the raspberry pi, but when I try to use the write() method, it isn't working:

baddr = 'xx:xx:xx:xx:xx:xx'
device = btle.Peripheral(baddr,'random')
chars = device.getCharacteristics()

chars[9].read()

returns '\x00'

but
chars[9].write('02')

and
chars[9].write('\x02')

accomplish nothing, because if I issue again

chars[9].read()

again I get '\x00'

with gatttool in bash the following works:

gatttool -b xx:xx:xx:xx:xx:xx  -t random --char-write 0x001b -n 02

How can I pass data to a characteristic using the write() method?

Thanks!

read/write of HM-10 BLE serial module

Hi there!

I'm currently trying to read/write serial data from a HM10-BLE module.

The module is connected to my USB via an FTDI chip and I can read/write AT-commands.

I'm already able to write data via Bluetooth and can see the chars via my usb-interface but it does not seem to work the other way around.

Here are some details:

s9 bluepy # python btle.py 7C:66:9D:9A:6F:90
Connecting to: 7C:66:9D:9A:6F:90
Service  :
    Characteristic <2a05>
    -> Error from Bluetooth stack (comerr)
Service  :
    Characteristic 
    -> 'HMSoft'
    Characteristic <2a01>
    -> '\x00\x00'
    Characteristic <2a02>
    -> '\x00'
    Characteristic <2a03>
    -> '\x00\x00\x00\x00\x00\x00'
    Characteristic <2a04>
    -> 'P\x00\xa0\x00\x00\x00\xe8\x03'
Service  :
    Characteristic 
    -> '\x00'

I have 3 services with differet characteristics:

== 00001801-0000-1000-8000-00805f9b34fb ==
[]
== 00001800-0000-1000-8000-00805f9b34fb ==
[, , , , ]
== 0000ffe0-0000-1000-8000-00805f9b34fb ==
[]

So my data-channel seems to be 0000ffe0, writing here ends at my USB side.

Does anybody know how I'd be able to read? The read() on the data-channel just returns None.

My code:

import struct
from btle import UUID, Peripheral

class HM10(Peripheral):
    _ctrlUUID=UUID("00001800-0000-1000-8000-00805f9b34fb")
    _dataUUID=UUID("0000ffe0-0000-1000-8000-00805f9b34fb")
    
    def __init__(self, addr):
        Peripheral.__init__(self,addr)
        self.discoverServices()
        for cUUID in self.services:
            print("== %s =="%str(cUUID))
            print(self.getServiceByUUID(cUUID).getCharacteristics())
                
        self.ctrl_SRV=self.getServiceByUUID(self._ctrlUUID)
        self.data_SRV=self.getServiceByUUID(self._dataUUID)

        self.data = self.data_SRV.getCharacteristics()[0]
        
        #print("== CTRL ==")
        #print(self.ctrl_SRV.getCharacteristics())
        self.ctrl = self.ctrl_SRV.getCharacteristics()[0]


if __name__ == "__main__":
    import time

    cHM10 = HM10("7C:66:9D:9A:6F:90")
    cHM10.ctrl.write(struct.pack("B", 0xff))
    #cHM10.ctrl.write(struct.pack("B", 0))
    
    while True:
        print(cHM10.data.read())
        print(cHM10.data.write("%s\n\r"%str(time.time())))
        time.sleep(1.0)

Thanks for any hints!

Response time

Hi,

Have you got any idea about the response time of the method write from the characteristic class ?
By response time, I mean time from the call of this method until the reception from the Peripheral.

I wrote a simple program on a raspberry which receive data by udp and send it to a bluetooth peripheral using bluepy.
I measure 40ms in average between the udp sending and the bluetooth reception. I would like it to be a bit faster, so I try to improve my program on the raspberry.
I don't know if this response time is due to a bad implementation of the udp reception, I made a non blocking reception in a thread which fill a queue. In another thread this queue is read and send by bluetooth. But it seems that threads can be tricky and maybe I did something bad.
Or maybe this response time is normal and is due to the time taking by the write method to execute, I don't know. Have you ever measured it ?

Anyway, thanks for this API, your work really helped me a lot !

Accelerometer equation

Hi the accelerometer equation devides by 64.

I found this to be inacurate as it did not give a resultant acceleration of 1 g when the sensortag was still on a table. I changed the code to devide by 16 instead and got better output.

Please someone do a simple test to verify this.

Subscribing to notifications in the GATT client

Hi,

Could someone tell me how the GATT client has to subscribe to notifications ?. Writting 0x01 in the characteristic CCCD descriptor ?.

I don't understand the way to do this described in bluepy 0.9.0 documentation (working with notifications).

Thanks and regards.

mgmt_new_default() always fails (Raspberry Pi)

The Code in the main function which is related to the mgmt function always fails. However it doesnt affect connecting to Bluetooth (as long as the workaround from issue 72 is implemented)

Registration to notification

Hi I am writing a program that register for a notification, I register the delegate and after try to register for notification calling write('\x01\x00') as noted in another issue and described in the bluetooth 4.0 rfc.
But it doesn't work, any notification for the characteristic is received. Is there an error in the small snippet I wrote? Thank you so much.

class MyDelegate(btle.DefaultDelegate):

    def __init__(self, hndl):
        btle.DefaultDelegate.__init__(self)
   self.hndl=hndl;

   def handleNotification(self, cHandle, data):
   if (cHandle==self.hndl):
            val = binascii.b2a_hex(data)
            val = binascii.unhexlify(val)
            val = struct.unpack('f', val)[0]
            print str(val) + " deg C"


p = btle.Peripheral("xx:xx:xx:xx", "random")

try:
   srvs = (p.getServices());
       chs=srvs[2].getCharacteristics();
      ch=chs[1];
  print(str(ch)+str(ch.propertiesToString()));
  p.setDelegate(MyDelegate(ch.getHandle()));
      # Setup to turn notifications on, e.g.
  ch.write("\x01\x00");

# Main loop --------
  while True:
      if p.waitForNotifications(1.0):
      continue

    print "Waiting..."
    # Perhaps do something else here
 finally:
    p.disconnect();

Scanning?

Hey Ian,

Have you given much thought to adding low-energy scanning to bluepy? I saw it in your TODO's, and I'm wondering whether you have a sense of what it would take (time, roadblocks, etc). I've been considering taking this on and have done a bit of research, but, if you've already started, I'd like to pick your brain.

Thanks,
Oren

Support for latest bluez source code tree

I tried to build bluepy-helper against the current bluez source tree (bluez-5.29). It was straightforward to point the makefile at that source tree, but I got a raft of errors and did not pursue it further.

gcc -L. -O0 -g -DHAVE_CONFIG_H -I../bluez-5.29/attrib -I../bluez-5.29 -I../bluez-5.29/lib -I../bluez-5.29/src -I../bluez-5.29/gdbus -I../bluez-5.29/btio `pkg-config glib-2.0 dbus-1 --cflags` -o bluepy-helper bluepy-helper.c ../bluez-5.29/lib/bluetooth.c ../bluez-5.29/lib/hci.c ../bluez-5.29/lib/sdp.c ../bluez-5.29/lib/uuid.c ../bluez-5.29/attrib/att.c ../bluez-5.29/attrib/gatt.c ../bluez-5.29/attrib/gattrib.c ../bluez-5.29/attrib/utils.c ../bluez-5.29/btio/btio.c ../bluez-5.29/src/log.c `pkg-config glib-2.0 --libs`
bluepy-helper.c:25:20: fatal error: config.h: No such file or directory
 #include "config.h"
                    ^
compilation terminated.
../bluez-5.29/lib/bluetooth.c:27:20: fatal error: config.h: No such file or directory
 #include <config.h>
                    ^
compilation terminated.
../bluez-5.29/lib/hci.c:27:20: fatal error: config.h: No such file or directory
 #include <config.h>
                    ^
compilation terminated.
../bluez-5.29/lib/sdp.c:28:20: fatal error: config.h: No such file or directory
 #include <config.h>

Upgrade to BlueZ-5.35

I tried to replace the bluez-5.29 in this package, with the latest bluez-5.35 release.
Got compile error in "bluepy-helper.c", line 462. Made minor change there, and it
seems to work. I just set the new flag passed to the subroutine as "false". That
should be OK as it is for an external encryption option.

Just in case you want to upgrade and test it, below were the chaanges:

sudo leafpad Makefile (Change Bluez version's Directory)
BLUEZ_PATH=../bluez-5.35
sudo leafpad bluepy-helper.c (Add "false" for a 3rd/new parameter RE external encryption)
Line 462: attrib = g_attrib_new(iochannel, mtu, false);

IRsensor (sensortag) raise math domain error

Running the example code on my sensortag, after a few succesful read, I had:

File "sensortag.py", line 196, in <module>
    ir, hum, baro = [ s.read() for s in sensors ]
  File "sensortag.py", line 196, in <listcomp>
    ir, hum, baro = [ s.read() for s in sensors ]
  File "sensortag.py", line 67, in read
    tObj = math.pow( math.pow(tDie,4.0) + (fObj/S), 0.25 )
ValueError: math domain error

I suspect S==0. I will try to confirm that

python3.2 crash

Hi,

I have the following crash with python3.2:

Traceback (most recent call last):
File "./home.py", line 8, in
import sensortag
File "/home/pi/apps/bluepy/bluepy/sensortag.py", line 1, in
from btle import UUID, Peripheral
File "/home/pi/apps/bluepy/bluepy/btle.py", line 344, in
UUID(0x1811, "Alert Notification Service"),
File "/home/pi/apps/bluepy/bluepy/btle.py", line 58, in init
self.binVal = binascii.a2b_hex(val)
TypeError: 'str' does not support the buffer interface

I think the following fixes it:

git diff
diff --git a/bluepy/btle.py b/bluepy/btle.py
index 7226c47..31b4328 100644
--- a/bluepy/btle.py
+++ b/bluepy/btle.py
@@ -55,7 +55,7 @@ class UUID:
if len(val) <= 8: # Short form
val = ("0" * (8 - len(val))) + val + "00001000800000805F9B34FB"

  •    self.binVal = binascii.a2b_hex(val)
    
  •    self.binVal = binascii.a2b_hex(bytes(val, "ascii"))
     if len(self.binVal) != 16:
         raise ValueError(
             "UUID must be 16 bytes, got '%s' (len=%d)" % (val,
    
    @@ -175,7 +175,7 @@ class Peripheral:
    elif tval[0]=="h":
    val = int(tval[1:], 16)
    elif tval[0]=='b':
  •            val = binascii.a2b_hex(tval[1:])
    
  •            val = binascii.a2b_hex(bytes(tval[1:], "ascii"))
         else:
             raise BTLEException(BTLEException.INTERNAL_ERROR,
                          "Cannot understand response value %s" % repr(tval))
    

and it has no downside since you just use a2b_hex for data/numerical values.

Add information about Python version support

It would be nice if the supported Python versions were displayed in the Readme. I took a look through closed issues and based on that I think this package supports Python 3.3+, but the setup.py only mentions Python 2.7.

Any more application details?

Hi Gents:

I came across this package (bluepy) in my quest to get some BLE Python apps created & up & running using the rpi and V4.0 USB dongle. Until now, I haven't seen much in the way of doing BLE & I'm no Bluetooth expert. But it seems like the ideal, low cost interface, when battery power is critical. Just have some ideas to send some data from place to place...Are there any more examples or commentary in setting up & using bluepy?

problem running two instances of sensortag.py in parallel on 3.2 linux kernel

I have two copies of sensortag.py - each copy has its own BLE ID it listens to.
If only one Sensor Tag is powered on then its assigned sensortag.py works fine - the other does not because its associated device is not running. This works also if I swap sensotag.pys and devices.

When I launch two devices and one sensortag.py then the program is still behaving as expected.
As soon as I run the second sensortag.py, everything breaks.

the stack trace I get is:

File "sensortag.py", line 203, in
ir, hum, baro, gyro = [ s.read() for s in sensors ]
File "sensortag.py", line 60, in read
(rawVobj, rawTamb) = struct.unpack('<hh', self.data.read())
File "/root/sensors/bluepy/bluepy/btle.py", line 114, in read
return self.peripheral.readCharacteristic(self.valHandle)
File "/root/sensors/bluepy/bluepy/btle.py", line 296, in readCharacteristic
resp = self._getResp('rd')
File "/root/sensors/bluepy/bluepy/btle.py", line 210, in _getResp
raise BTLEException(BTLEException.COMM_ERROR, "Error from Bluetooth stack (%s)" % errcode)
btle.BTLEException: Error from Bluetooth stack (comerr)

The only file that I've modified is sensortag.py. The change was tiny and only related to the device ID.

Is bluepy working in some kind of single connection mode? Is there a way I could find the root cause? What would be the best workaround for reading from multiple sensorTags without making big changes to the bluepy internals?

Connection doesn't happen

Hi,

I'm trying to run your lib on RPi. I removed everything and just put
conn = Peripheral("72:64:9D:DB:0A:11")

and I get

Running  /home/pi/BT/LE/sandbox/bluepy-helper
Sent:  conn 72:64:9D:DB:0A:11

Got: '# bluepy-helper.c built at 12:26:47 on Apr 11 2014\n'
Got: "rsp=$stat state=$tryconn dst='72:64:9D:DB:0A:11 mtu=h0 sec='low\n"

Any idea why?
Is there any example code other than included btle.py?

Testing bluepy

I'm quite sure it's not an issue with bluepy, but I need confirmation. That's a discovery session with a heart rate sensor:
pi@occberry ~/bluepy/bluepy $ sudo hciconfig hci0 up
pi@occberry ~/bluez/bluez-5.26 $ sudo hcitool lescan
LE Scan ...
90:59:AF:16:93:12 (unknown)
90:59:AF:16:93:12 JipulseHrRateBT4.0
[..]
pi@occberry ~/bluepy/bluepy $ sudo python btle.py 90:59:AF:16:93:12
Connecting to: 90:59:AF:16:93:12
Service <uuid=Generic Attribute handleStart=12 handleEnd=15> :
Characteristic <2a05>
-> Error from Bluetooth stack (comerr)
Service <uuid=Generic Access handleStart=1 handleEnd=11> :
Characteristic
-> ''
Characteristic <2a01>
-> '\x00\x00'
Characteristic <2a02>
-> '\x00'
Characteristic <2a03>
-> '\x00\x00\x00\x00\x00\x00'
Characteristic <2a04>
-> 'P\x00\xa0\x00\x00\x00\xe8\x03'
Service <uuid=ffe0 handleStart=52 handleEnd=65535> :
Characteristic
-> Error from Bluetooth stack (comerr)
Service <uuid=fff0 handleStart=35 handleEnd=51> :
Characteristic
-> '\x01'
Characteristic
-> '\x02'
Characteristic
-> Error from Bluetooth stack (comerr)
Characteristic
-> Error from Bluetooth stack (comerr)
Characteristic
-> Error from Bluetooth stack (comerr)
Service <uuid=Device Information handleStart=16 handleEnd=34> :
Characteristic <2a23>
-> '\x12\x93\x16\x00\x00\xafY\x90'
Characteristic
-> 'Model Number\x00'
Characteristic
-> 'Serial Number\x00'
Characteristic
-> 'Firmware Revision\x00'
Characteristic
-> 'Hardware Revision\x00'
Characteristic
-> 'Software Revision\x00'
Characteristic
-> 'Manufacturer Name\x00'
Characteristic <2a2a>
-> '\xfe\x00experimental'
Characteristic <2a50>
-> '\x01\r\x00\x00\x00\x10\x01'

Does it look OK conparing to other BLE devices?
That sensor doesn't work properly with android, so I guess that the vendor at least partially ignored BLE specification. P.S. Running the bluepy-helper doesn't make any difference.

Running constructor returns an error

Update 2014-03-08: I built the BluePy again after installing Bluez5.4 and now I do not get the error anymore! It was because of my lack of knowledge. So please close this issue!

Running RPi with Raspbian distro and Bluez5.28 drivers

When I run the python code at the bottom I get the following result:

pi@pi ~/Desktop/bletest $ python BluePyTest.py 
Running  /usr/local/lib/python2.7/dist-packages/bluepy-helper
Traceback (most recent call last):
  File "BluePyTest.py", line 22, in <module>
    bean = btle.Peripheral(address)
  File "/usr/local/lib/python2.7/dist-packages/btle.py", line 190, in __init__
    self.connect(deviceAddr, addrType)
  File "/usr/local/lib/python2.7/dist-packages/btle.py", line 294, in connect
    self._startHelper()
  File "/usr/local/lib/python2.7/dist-packages/btle.py", line 201, in _startHelper
    universal_newlines=True)
  File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1259, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

The python code BluePyTest.py:

import sys
import btle

class MyDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)
        # ... initialise here

    def handleNotification(self, cHandle, data):
        # ... perhaps check cHandle
        # ... process 'data'
        print "Received notification:"
        print cHandle
        print "Data:"
        print data

# Initialisation  -------

address = "6F:33:41:AA:C2:AB"

bean = btle.Peripheral(address)

# more code below, but not relevant here.

Is this because I have configured it wrong? I can not get it to play.

Probable cause: BluePy not supporting Bluez5.28? I tried to make the BluePy once more changing the Makefile Bluez path to a prebuilt Bluez5.28. This returned an error:

pi@pi ~/Desktop/bluepy/bluepy/bluepy $ make
gcc -L. -O0 -g -DHAVE_CONFIG_H -I..//../../bluez/bluez-5.28/attrib -I..//../../bluez/bluez-5.28 -I..//../../bluez/bluez-5.28/lib -I..//../../bluez/bluez-5.28/src -I..//../../bluez/bluez-5.28/gdbus -I..//../../bluez/bluez-5.28/btio `pkg-config glib-2.0 dbus-1 --cflags` -o bluepy-helper bluepy-helper.c ..//../../bluez/bluez-5.28/lib/bluetooth.c ..//../../bluez/bluez-5.28/lib/hci.c ..//../../bluez/bluez-5.28/lib/sdp.c ..//../../bluez/bluez-5.28/lib/uuid.c ..//../../bluez/bluez-5.28/attrib/att.c ..//../../bluez/bluez-5.28/attrib/gatt.c ..//../../bluez/bluez-5.28/attrib/gattrib.c ..//../../bluez/bluez-5.28/attrib/utils.c ..//../../bluez/bluez-5.28/btio/btio.c ..//../../bluez/bluez-5.28/src/log.c `pkg-config glib-2.0 --libs`
bluepy-helper.c: In function ‘connect_cb’:
bluepy-helper.c:225:2: error: too few arguments to function ‘g_attrib_new’
..//../../bluez/bluez-5.28/attrib/gattrib.h:45:10: note: declared here
bluepy-helper.c: In function ‘char_desc_cb’:
bluepy-helper.c:357:9: error: incompatible types when assigning to type ‘bt_uuid_t’ from type ‘int’
bluepy-helper.c:359:9: error: incompatible types when assigning to type ‘bt_uuid_t’ from type ‘int’
bluepy-helper.c: In function ‘cmd_connect’:
bluepy-helper.c:474:7: error: too few arguments to function ‘gatt_connect’
..//../../bluez/bluez-5.28/attrib/gatttool.h:26:13: note: declared here
bluepy-helper.c: In function ‘cmd_primary’:
bluepy-helper.c:497:3: warning: passing argument 3 of ‘gatt_discover_primary’ from incompatible pointer type [enabled by default]
..//../../bluez/bluez-5.28/attrib/gatt.h:76:7: note: expected ‘gatt_cb_t’ but argument is of type ‘void (*)(struct GSList *, guint8,  void *)’
bluepy-helper.c:506:2: warning: passing argument 3 of ‘gatt_discover_primary’ from incompatible pointer type [enabled by default]
..//../../bluez/bluez-5.28/attrib/gatt.h:76:7: note: expected ‘gatt_cb_t’ but argument is of type ‘void (*)(struct GSList *, guint8,  void *)’
bluepy-helper.c: In function ‘cmd_included’:
bluepy-helper.c:549:2: warning: passing argument 4 of ‘gatt_find_included’ from incompatible pointer type [enabled by default]
..//../../bluez/bluez-5.28/attrib/gatt.h:79:14: note: expected ‘gatt_cb_t’ but argument is of type ‘void (*)(struct GSList *, guint8,  void *)’
bluepy-helper.c: In function ‘cmd_char’:
bluepy-helper.c:586:3: warning: passing argument 5 of ‘gatt_discover_char’ from incompatible pointer type [enabled by default]
..//../../bluez/bluez-5.28/attrib/gatt.h:82:7: note: expected ‘gatt_cb_t’ but argument is of type ‘void (*)(struct GSList *, guint8,  void *)’
bluepy-helper.c:590:2: warning: passing argument 5 of ‘gatt_discover_char’ from incompatible pointer type [enabled by default]
..//../../bluez/bluez-5.28/attrib/gatt.h:82:7: note: expected ‘gatt_cb_t’ but argument is of type ‘void (*)(struct GSList *, guint8,  void *)’
Makefile:23: recipe for target 'bluepy-helper' failed
make: *** [bluepy-helper] Error 1

Can you add a .gitignore?

I am using your library in one of my projects as a submodule, and it screws up the git updating when there is no .gitignore.

Could you add at least the following:

# .gitignore file
__pycache__
.DS_Store

Thanks!

Connect fails immediately if another connect is pending.

I realize I may be pushing the limits of how this is intended to work, and am using a modified bluepy, but here goes: The short version is that if a bluepy connection is pending (e.g., the receiver is powered off and we're waiting for it to time out), other connection attempts--in separate btle objects, with their own bluepy-helper processes--immediately fail.

I'm using a single python application to communicate with multiple BLE devices. Now normally you can't get into the state I described above (multiple pending connects) because connect() blocks. You might be able to get there by using threads, but for various reasons I took a different approach, and made my own asynchronous connect method. connect_async() initiates the connect, and you can poll a second method to detech when and how connect completes (either successfully or not). Aside from the problem described here, this appears to work perfectly. If all receivers are up, or if I wait for the first connection to fail before initiating the second connection, then they all connect and operate simultaneously as expected.

So in my code, the steps that cause this are:

  1. Instantiate btle object btleA.
  2. Instantiate btle object btleB.
  3. Call btleA.connect_async()
  4. Call btleB.connect_async()
  5. Immediate failure of btleB connection.
  6. If you wait until btleA connection times out and call btleB.connect_async() again, it connects fine.

When it fails this way, it prints the following message:
connect: Device or resource busy (16)

I believe I have tracked this to the connect() call in bluez btio.c line 360 (and output at like 1433), but I don't know enough about bluez to really dig further.

FWIW, I just tried it on the testing/bluez-5.29 branch, and it behaved exactly the same.

Thanks for any help, and let me know if you need additional info or if there's a better way I should be doing all of this; I realize this is a bit scattered. I'm also happy to share my async connection code, though it isn't robust and I'm 90% it's not the direct cause of the issue.

How to write to a Characteristic

Not really an Issue, but I have a question:
The device I am trying to communicate with requires that I set the value of a characteristic and then write to the characteristic. The response from this write contains the result of the command. For instance if I write "read temp\r" I get back "66.0". I have looked through your code, but not being an expert in Python, I am having a bit of a time figuring out how I write a string (like "status") to the characteristic and then get back the response. I am pretty sure this is something simple, but I am stuck.

Device disconnects when running getServices() but works fine with other methods

Hey Ian,

I'm having an issue when trying get or discover services. I can establish the connection without an issue:

>>> conn = Peripheral("5C:F3:70:62:FE:5D", "public")
Running  /home/pi/GitHub/bluepy/bluepy/bluepy-helper
Sent:  conn 5C:F3:70:62:FE:5D public

Got: '# bluepy-helper.c built at 22:58:35 on Jun  8 2015\n'
Got: "rsp=$stat state=$tryconn dst='5C:F3:70:62:FE:5D mtu=h0 sec='low\n"
Got: "rsp=$stat state=$conn dst='5C:F3:70:62:FE:5D mtu=h0 sec='low\n"'

Then calling getServices() or discoverServices() causes the device to disconnect:

>>> conn.discoverServices()
Sent:  svcs

Got: "rsp=$stat state=$disc mtu=h0 sec='low\n"
Stopping  /home/pi/GitHub/bluepy/bluepy/bluepy-helper
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "btle.py", line 325, in discoverServices
    rsp = self._getResp('find')
  File "btle.py", line 286, in _getResp
    raise BTLEException(BTLEException.DISCONNECTED, "Device disconnected")
btle.BTLEException: Device disconnected

But calling getCharacteristics() works fine:

 >>> conn.getCharacteristics()
 Sent:  char 1 FFFF

Got: "rsp=$find hnd=h4 props=h2 vhnd=h6 uuid='00002a00-0000-1000-8000-00805f9b34fb hnd=h7     props=h2 vhnd=h8 uuid='00002a01-0000-1000-8000-00805f9b34fb hnd=hFFFD props=h1A   vhnd=hFFFE uuid='faf69fd8-d058-45e3-a06e-86662c8c7918\n"
[<btle.Characteristic instance at 0x76abce40>, <btle.Characteristic instance at 0x76abe0a8>,     <btle.Characteristic instance at 0x76abe170>]

And calling getDescriptors works (minus it seeming to hang at the end):

 >>> conn.getDescriptors()
Sent:  desc 1 FFFF

Got: "rsp=$desc hnd=h1 uuid='2800 hnd=h4 uuid='2803 hnd=h6 uuid='2a00 hnd=h7 uuid='2803 hnd=h8 uuid='2a01\n"
Got: "rsp=$desc hnd=h10 uuid='2800 hnd=hFFFC uuid='2800 hnd=hFFFD uuid='2803\n"
Got: "rsp=$desc hnd=hFFFE uuid='faf69fd8-d058-45e3-a06e-86662c8c7918\n"
Got: "rsp=$desc hnd=hFFFF uuid='2902\n"

Any ideas on why the device disconnects? Thanks!

Needs a way to pick which adapter to use.

If the system has a bluetooth adapter which doesn't support LE there is no way to tell bluepy to not use it. It always tries to use the one most recently connected to the system.

Licence

Are you OK to use your code in an GPLv3 project? I'm working on an open software/hardware cycling computer (raspberry pi + PiTFT + pygame) and looks like your code will be perfect to impelment speed, cadence and heart reate measurements from BLE sensors.

Notifications?

Hi Ian,

I like a lot your code, because it is very elegant and nice. I have using it but I have some speed issues that I think that would be solved activating the notification mode of the sensors in a ST. Do you have any suggestion about it? Any plan to continue this project in this line?

Thanks for your work.

Support for Mac OS X (10.9, 10.10)

bluepy and bluepy-helper depend on Linux's bluez.

It would be a useful thing to have an abstraction layer that let you write the same python code for both Mac OS X and Linux, along the lines of what noble does for node.js.

Tracking any specific issues here.

Support python 3.4

I amended btle.py with some support for py3.4, I'll do a pull request at some point in the future.
Feel free to see my fork's branch "py3". I had to reformat many things, as they broke on python 3.4.
I took the chance to have them formatted as much I could with pylint, pep8 and pep257, as I'm planning to use the code later.

Back compatible with 2.7 in theory, I tried it out and it works, but there are no unit tests so it's hard to say.

raw BLE advertisement scanning

Hi Ian

I noticed the comment below on your readme for the project:

- Implement 'hcitool lescan' functionality

Are you aware of any python libs that will expose the raw advertisement payloads?
Any idea if / when yours may?

Thanks!

Can't compile bluepy on Raspberry Pi

Sorry if this is a simple question but I am having trouble compiling bluepy on Raspberry Pi:

Already installed libraries:
pi@rasp01 ~ $ sudo apt-get install build-essential libglib2.0-dev libdbus-1-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
build-essential is already the newest version.
libdbus-1-dev is already the newest version.
libglib2.0-dev is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 40 not upgraded.

Cloned bluepy:
pi@rasp01 - $ git clone https://github.com/IanHarvey/bluepy.git
pi@rasp01 - $ cd bluepy/bluepy

And tried to compile the source (this is where I ran into problems):
pi@rasp01 ~/bluepy/bluepy $ make
gcc -L. -Os -g -Wall -Werror -DHAVE_CONFIG_H -I../bluez-5.33/attrib -I../bluez-5.33 -I../bluez-5.33/lib -I../bluez-5.33/src -I../bluez-5.33/gdbus -I../bluez-5.33/btio pkg-config glib-2.0 dbus-1 --cflags -o bluepy-helper bluepy-helper.c ../bluez-5.33/lib/bluetooth.c ../bluez-5.33/lib/hci.c ../bluez-5.33/lib/sdp.c ../bluez-5.33/lib/uuid.c ../bluez-5.33/attrib/att.c ../bluez-5.33/attrib/gatt.c ../bluez-5.33/attrib/gattrib.c ../bluez-5.33/attrib/utils.c ../bluez-5.33/btio/btio.c ../bluez-5.33/src/log.c ../bluez-5.33/src/shared/mgmt.c ../bluez-5.33/src/shared/crypto.c ../bluez-5.33/src/shared/att.c ../bluez-5.33/src/shared/queue.c ../bluez-5.33/src/shared/util.c ../bluez-5.33/src/shared/io-glib.c ../bluez-5.33/src/shared/timeout-glib.c pkg-config glib-2.0 --libs
bluepy-helper.c: In function âconnect_cbâ:
bluepy-helper.c:462:2: error: too few arguments to function âg_attrib_newâ
../bluez-5.33/attrib/gattrib.h:45:10: note: declared here
bluepy-helper.c: In function âcmd_pairâ:
bluepy-helper.c:1180:7: error: unused variable âaddrâ [-Werror=unused-variable]
bluepy-helper.c: In function âcmd_unpairâ:
bluepy-helper.c:1230:7: error: unused variable âaddrâ [-Werror=unused-variable]
bluepy-helper.c: In function âmgmt_debugâ:
bluepy-helper.c:1396:14: error: unused variable âprefixâ [-Werror=unused-variable]
cc1: all warnings being treated as errors
Makefile:26: recipe for target 'bluepy-helper' failed
make: *** [bluepy-helper] Error 1

I am using bluez-5.33 instead of 5.29.

Any insight would be much appreciated.

Thank you!!!

line_reader is not working

The newest merge seems to have broken the _getResp() method. With the following test code:

from bluepy.btle import Peripheral
p = Peripheral("xx:xx:xx:xx:xx:xx")

I get the following error:

File "/home/edison/bluepy/bluepy/btle.py", line 188, in init
self.connect(deviceAddr, addrType)
connect: Device or resource busy (16)
File "/home/edison/bluepy/bluepy/btle.py", line 298, in connect
rsp = self._getResp('stat')
File "/home/edison/bluepy/bluepy/btle.py", line 250, in _getResp
rv = ''.join(map(chr, rv))
TypeError: an integer is required
Exception TypeError: 'an integer is required' in <bound method Peripheral.del of <bluepy.btle.Peripheral instance at 0xb72b98ec>> ignored

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.