User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Mon Jul 30, 2018 5:01 pm

ok so i backed up from scripting the commands to using bluetoothctl to make sure they work again.

I tried notifications in this way but i still get 00.

Is there a special way to read notifications with bluetoothctl?

Code: Select all

[BT Bee-BLE:/service0010/char0011]# notify on
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Notifying: yes
Notify started
[CHG] Device 5D:45:13:FC:7C:59 RSSI: -82
[CHG] Device 00:0E:0E:00:75:12 RSSI: -71
[BT Bee-BLE:/service0010/char0011]# write 0x5B
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Value:
  00                                               .               
[CHG] Device C1:7F:AA:E8:DA:5C RSSI: -78
[CHG] Device C1:7F:AA:E8:DA:5C ManufacturerData Key: 0x0157
[CHG] Device C1:7F:AA:E8:DA:5C ManufacturerData Value:
  00 d8 f7 ed 39 ad 97 4e 8a 35 ef 0b f3 5e fd ea  .???9?.N.5?.?^??
  0d 02 c1 7f aa e8 da 5c                          ..?.???\        
[CHG] Device 00:0E:0E:00:75:12 RSSI: -58
[BT Bee-BLE:/service0010/char0011]# write 0x5B
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Value:
  00                                               .               
[BT Bee-BLE:/service0010/char0011]# write 0x5B 0x00 0x00 0x00
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Value:
  00                                               .   
============

Ok I just tried other commands found here, (https://www.tinyosshop.com/datasheet/TS ... manual.pdf) and I think they work.

0x5A should return module id and software version, I get 0f and 01. Not sure if thats right, but at least it returns 2 bytes as expected.
0x5D should return the operating voltage of the relay board which is 12, well it returns 32, but again, at least its 1 byte.

I also tried 0x65 and it activated the 1st relay, but by terminal window got stuck. It might be an issue of my ssh connection to the rpi...yeah it was a Lan issue. It doesn't get stuck anymore.

So it seems to be just that particular one:

Code: Select all

[BT Bee-BLE:/service0010/char0011]# write 0x5A
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Value:
  0f 01                                            ..              
[BT Bee-BLE:/service0010/char0011]# write 0x5D
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Value:
  32                            
Ok Im getting the notification I think as seen here, but it still contains 00. It might be my interpretation of it then because if I get attribute-info the value for it is 00 as well:

Code: Select all

[BT Bee-BLE]# select-attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010
[BT Bee-BLE:/service0010]# select-attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[BT Bee-BLE:/service0010/char0011]# write 0x6F
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[BT Bee-BLE:/service0010/char0011]# write 0x5B
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[BT Bee-BLE:/service0010/char0011]# write 0x5B
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[BT Bee-BLE:/service0010/char0011]# acquire-notify
[CHG] Attribute /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 NotifyAcquired: yes
AcquireNotify success: fd 7 MTU 23
[BT Bee-BLE:/service0010/char0011]# write 0x5B
Attempting to write /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
[CHG] /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011 Notification:
  00                                               .               
[BT Bee-BLE:/service0010/char0011]# attribute-info /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010/char0011
Characteristic - Unknown
	UUID: 0000ffe1-0000-1000-8000-00805f9b34fb
	Service: /org/bluez/hci0/dev_00_0E_0B_00_75_12/service0010
	Value:
  00                                               .               
	Notifying: no
	Flags: read
	Flags: write-without-response
	Flags: notify
[BT Bee-BLE:/service0010/char0011]# 
So where did I get that idea that I should get a list or array as a response? Well:

1. Because it seems logical to have a 4 channel relay bt device to respond with such data in order to know the state of the relays.

2. Because when I used to have an rpi2 with an hm10 module hardwired to gpio pins for tx and rx and connected to the tsrb board using this code I would get this as a result:
{1: 0, 2: 0, 3: 0, 4: 0}
Using this code :

Code: Select all

#!/usr/bin/env python

import serial

def convert_hex_to_int(hexChars):
    #convert string of hex chars to a list of ints
    try:
        ints = [ord(char) for char in hexChars]
        return ints
    except TypeError:
        pass
    return []
def convert_hex_to_bin_str(hexChars):
    #convert hex char into byte string
    response = convert_hex_to_int(hexChars)[0]
    # convert int to binary string
    responseBinary = bin(response)
    # first 2 chars of binary string are '0b' so ignore these
    return responseBinary[2:]

ser = serial.Serial(
	port='/dev/serial0',
	baudrate=9600,
	parity=serial.PARITY_NONE,
	stopbits=serial.STOPBITS_ONE,
	bytesize=serial.EIGHTBITS,
	timeout=1
)

print "Serial is open: " + str(ser.isOpen())

print "Now Writing"
ser.write("[")
#ser.write("AT+CONNL")
print "Did write, now read"
x = ser.readline()
print "got '" + x + "'"

responseBits = convert_hex_to_bin_str (x)
# binary conversion drops values until a 1 is encountered
# assume missing values are 0 and pad to give a value for all relays
responseBits = responseBits.zfill(4)
# reverse chars so that relay 1 is first
responseBits = list(responseBits)
responseBits.reverse()
# create dictionary of relay states
relayStates = {}
relay = 1
for bit in responseBits:
    relayStates[relay] = int(bit)
    relay += 1
print relayStates

ser.close()

User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Mon Aug 13, 2018 2:21 am

Hello? Help please

User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Sat Sep 08, 2018 1:09 am

Please I need help writing python to read response from a ble device.

PhatFil
Posts: 511
Joined: Thu Apr 13, 2017 3:55 pm

Re: Reading response from BLE device on rpi3

Sat Sep 08, 2018 4:37 pm

You have surpassed my toe dipping into this subject by a long way now, thankfully the devices i have interfaced with have had all the hard work like this done already.. While its not the best help , all i can suggest is for python specific issues perhaps the python list here https://python-forum.io could help, they have been helpful to me in the past.

your tenacity is to be admired and i hope it will rewarded with success soon.

here is another successful pi/ble device interfacing project that may shed some light? GitHub may be worth a search/trawl your solution could be there badly labeled??

https://zsiti.eu/xiaomi-mijia-hygrother ... pberry-pi/.

User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Sun Sep 09, 2018 3:06 am

Thanks

I dont believe its a python issue as I havent been able to get the ble relay board (device) to respond or be able to read its characteristic data via bluetoothctl either. This is what I know so far:

1. The ble device (relayboard) can talk to any of the BLE android apps out there and I can read and write to it in order to activate its relays by sending ascii characters like "e" and "o" as the manual instructs.

2. The ble device can also be instructed to activate its relays via bluetoothctl.

3. The ble device can also be commanded via python file such as

Code: Select all

c.write("o", "utf-8")
.

4. The problem is reading from it. When I communicated with the ble device from a rpi2 with a serial gpio pin connected hm10, I was able to send the command

Code: Select all

ser.write("[")
and sending whatever this returned

Code: Select all

x = ser.readline()
to a function that converted that hex response to int or that response to binary and that returned an array like {1: 0, 2: 0, 3: 0, 4: 0}

5. My main doubt is whether the data can be read, by simply reading a characteristic off the device. From what Douglas6 suggested and from my old working code on the rpi2 it seems that the ble device responds to the command "[" . The issue is how do I read that response...oh, i get what you say, I might just have to pass the results to python for parsing like my old code...

Ok I just tried this code:

Code: Select all

#!/usr/bin/env python
import bluepy.btle as btle

#helper functions####################################
def convert_hex_to_int(hexChars):
    #convert string of hex chars to a list of ints
    try:
        ints = [ord(char) for char in hexChars]
        return ints
    except TypeError:
        pass
    return []
def convert_hex_to_bin_str(hexChars):
    #convert hex char into byte string
    response = convert_hex_to_int(hexChars)[0]
    # convert int to binary string
    responseBinary = bin(response)
    # first 2 chars of binary string are '0b' so ignore these
    return responseBinary[2:]
#helper functions#########################################

#Create peripheral, connect, services and write...
p = btle.Peripheral("00:0E:0B:00:75:12", "random")
services=p.getServices()
for service in services:
   print service
s = p.getServiceByUUID("0000ffe0-0000-1000-8000-00805f9b34fb")
c = s.getCharacteristics()[0]
c.write("[")
x = c.read()

#parse read with helper functions#########################
responseBits = convert_hex_to_bin_str (x)
# binary conversion drops values until a 1 is encountered
# assume missing values are 0 and pad to give a value for all relays
responseBits = responseBits.zfill(4)
# reverse chars so that relay 1 is first
responseBits = list(responseBits)
responseBits.reverse()
# create dictionary of relay states
relayStates = {}
relay = 1
for bit in responseBits:
    relayStates[relay] = int(bit)
    relay += 1
print relayStates
and got this response:
{1: 0, 2: 0, 3: 0, 4: 0}
which is incorrect because relay 1 is on, so it should have a 1 instead of a 0. I guess Ill have to debug.


Reference
a-https://www.raspberrypi.org/forums/view ... 8&start=25
b-https://www.raspberrypi.org/forums/view ... 9#p1327039

PhatFil
Posts: 511
Joined: Thu Apr 13, 2017 3:55 pm

Re: Reading response from BLE device on rpi3

Mon Sep 10, 2018 2:59 am

I hesitate to suggest this as its a node-red solution which if your not familiar with node red or java script, could be a bit of an up hill battle coming to terms with a new system and programing paradigm while also trying to learn a new coms protocol. But on a casual glance through it does provide all the features you want.. If it will read data that better represents the actual state of the relay board????
https://flows.nodered.org/node/node-red ... eneric-ble
(btw if considering installing node red, do so via the instructions on the node-red pi page, and regardless of what packages such as the one i have linked to says install all new nodes through the gui interface and the manage palette option when possible.

User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Tue Sep 11, 2018 4:32 pm

So I took this part of the python code:

Code: Select all

s = p.getServiceByUUID("0000ffe0-0000-1000-8000-00805f9b34fb")
c = s.getCharacteristics()[0]
c.write("[")
x = c.read()

#parse read with helper functions#########################
responseBits = convert_hex_to_bin_str (x)
and inserted a print x right between the x=c.read() and the responseBits.... in order to print the raw response from the ble device, but I just got a blank line printed on the terminal. Dunno if that means the ble didnt respond to the "[" or if it responded with a blank line?

Ill keep messing with it.

User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Tue Sep 11, 2018 9:29 pm

Ok I tried this readline() instead of read() and i get this error:

Code: Select all

Hallo from Peripheral
discovering services
Hello
Service <uuid=Generic Attribute handleStart=12 handleEnd=15>
Service <uuid=Generic Access handleStart=1 handleEnd=11>
commonName= 0000ffe0-0000-1000-8000-00805f9b34fb
commonName= ffe0
Service <uuid=ffe0 handleStart=16 handleEnd=65535>
65535
Traceback (most recent call last):
  File "readble.py", line 40, in <module>
    x = c.readline()
AttributeError: Characteristic instance has no attribute 'readline'
my code:

Code: Select all

import bluepy.btle as btle

#helper functions####################################
def convert_hex_to_int(hexChars):
    #convert string of hex chars to a list of ints
    try:
        ints = [ord(char) for char in hexChars]
        return ints
    except TypeError:
        pass
    return []
def convert_hex_to_bin_str(hexChars):
    #convert hex char into byte string
    response = convert_hex_to_int(hexChars)[0]
    # convert int to binary string
    responseBinary = bin(response)
    # first 2 chars of binary string are '0b' so ignore these
    return responseBinary[2:]
#helper functions#########################################

p = btle.Peripheral("00:0E:0B:00:75:12", "random")
services=p.getServices()
for service in services:
   print service
s = p.getServiceByUUID("0000ffe0-0000-1000-8000-00805f9b34fb")
c = s.getCharacteristics()[0]
c.write("[")
x = c.readline()
print x

#parse read with helper functions#########################
responseBits = convert_hex_to_bin_str (x)
responseBits = responseBits.zfill(4)
responseBits = list(responseBits)
responseBits.reverse()

# create dictionary of relay states
relayStates = {}
relay = 1
for bit in responseBits:
    relayStates[relay] = int(bit)
    relay += 1
print relayStates
Just realized bluepy characteristic object doesnt support readlin() only read(). I also tried printing the supportsRead() and it came out True, so thats good news.

I think the issue remains that I was unable to read the characteristic using cli tool bluetoothctl. So since I was unable to get a proper response using bluetoothctl, I just tried the BLE Scanner app on iPhone again. Ive used this app before to toggle the relays on the relay board directly before.(whereas the rpi3 runs a py script to toggle those relays via a logic program that tells the rpi3 when to toggle each one).

When I enter the app it has 4 menus at the bottom and the app opens up into the first one called BLE Scanner from which I select the BLE device, connect to it, read through its services (where there is only the one custom service ffe0):
Screen Shot 2018-09-11 at 3.46.55 PM.png
Screen Shot 2018-09-11 at 3.46.55 PM.png (94.01 KiB) Viewed 176 times
and that takes me to a screen with a menu ffe1 where I can tap on Read,Notify,WriteWithoutResponse and that takes me to ffe0s write value or read value or notify screen and if I tap on Write, I can send hex or text which is where I enter "e" to toggle relay 1 on or "o" to toggle relay 1 off, etc:
Screen Shot 2018-09-11 at 3.47.04 PM.png
Screen Shot 2018-09-11 at 3.47.04 PM.png (87.43 KiB) Viewed 176 times
But when I tap on Read, i just get a new 0x00 entry, which means nothing, so right now I went over to the next menu item called Peripherals and found this screen:
Screen Shot 2018-09-11 at 3.47.14 PM.png
Screen Shot 2018-09-11 at 3.47.14 PM.png (79.46 KiB) Viewed 176 times
I dunno what Im looking for, or actually I do, Im looking for a way to read the device's response when I send it "[". But Im not sure how else to look for it.

User avatar
marciokoko
Posts: 276
Joined: Sat Aug 27, 2016 4:33 pm

Re: Reading response from BLE device on rpi3

Mon Sep 17, 2018 11:18 pm

I have this code so far:

Code: Select all

#!/usr/bin/env python
import bluepy.btle as btle

#Delegate methods
class ReadDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)

    def handleNotification(self, cHandle, data):
       print("Here is the data...")
       print("A notification was received: %s" %data)

#Create peripheral, connect, services and write...
p = btle.Peripheral("00:0E:0B:00:75:12", "random")
p.setDelegate(ReadDelegate())
services=p.getServices()
for service in services:
    print service

# Setup to turn notifications on, e.g.
s = p.getServiceByUUID("0000ffe0-0000-1000-8000-00805f9b34fb")
c = s.getCharacteristics()[0]
print(c.valHandle)

p.writeCharacteristic(c.valHandle+1, "\x5B\x00")

while True:
    if p.waitForNotifications(1.0):
        # handleNotification() was called
        continue
    print("Waiting...")
    # Perhaps do something else here
I get a response up to the part where it prints that a notification was received so I know its sort of working. I wanted to ask what that p.writeCharacteristic() is doing. The code I got it from had \x02\x00, but I replaced it with \x5B\x00 because 5B is the character that I need to send to cause the notification to be fired. But Im not sure that's how I should be sending it. At present Im getting this as a response:

Code: Select all

[email protected]:~/Documents/python/failedPythonBLE $ python notifications.py
Hallo from Peripheral
discovering services
Hello
Service <uuid=Generic Attribute handleStart=12 handleEnd=15>
Service <uuid=Generic Access handleStart=1 handleEnd=11>
commonName= 0000ffe0-0000-1000-8000-00805f9b34fb
commonName= ffe0
Service <uuid=ffe0 handleStart=16 handleEnd=65535>
65535
18
Here is the data...
A notification was received: 
Waiting...
Waiting...
Waiting...
All the way from "Hallo from Peripheral" to "Hello" is some debug code I added somewhere in the btle library (which btw I dont remember where). But as can be seen, the delegate is being called. 18 is the print(c.valHandle)...

I just tried sending \x02\x00 and then \x01\x00 and I get nothing in the terminal, not even the delegate callback. Only when I send \x5B\x00 do I get the "A notification was received:" line in the terminal as results. So it must be a matter of decoding the data sent so that i can be printed.

User avatar
Douglas6
Posts: 4453
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Reading response from BLE device on rpi3

Tue Sep 18, 2018 12:06 am

P.writeCharacteristic(handle, data) writes 'data' to the peripheral's characteristic with handle 'handle'. Useful if you don't have the characteristic, but you do, so doing c.write(data) is more explicit (better).

Except you're writing to the next characteristic, 'valHandle+1'. This is typical done to turn on notifications, although I don't believe it's necessary in your case. Assuming you have the proper characteristic, I would simply write to it instead. But I don't know enough about your device, and I'm not sure you do.

I would also simply print(data), which should be a list of bytes, instead of assuming it can be translated into a printable string.

Return to “Beginners”