Using Python, Gatttool, and BLE With Hexiwear
The combination of Python scripts, gatttool, BLE, and Hexiwear lets you send and access data over your devices with a few handy scripts.
If you've been following along with this series, now I can use the data on the Hexiwear over BLE with the gatttool. This article is taking things a step further and uses a Python script on Linux to access the sensor data on the BLE device:
This article is about accessing the Mikroelektronika Bluetooth Low Energy Hexiwear device with Python scripting from a Raspberry Pi. That way, it is possible to send and receive data over BLE and do whatever I want. The precondition is to have a working BLE connection and pairing with the Hexiwear using Bluez. Python is a powerful scripting language and can be used for all kind of automation.
Installation
I’m using Python with the ‘pexpect’ package. First, make sure that latest packages are used:
sudo apt-get update
Next, make sure the PIP (Python Package Package) is installed:
sudo apt-get install git build-essential python-dev python-pip
Install the pexpect, a package to control other applications from Python:
sudo pip install pexpect
I’m using here the 4.2 version of the pexpect package.
Pexpect
With 'pexpect', I can spawn a process from Python and then control it like I would type in the commands manually. With pexpect , I can run the gatttool as I would type the commands on a console/terminal.
Here are the basic building blocks to access the data on the Hexiwear with it.
The following Python variable is used to store the address of the BLE device used:
DEVICE = "00:32:40:08:00:12"
I run the gatttool with the -I (interactive) option:
child = pexpect.spawn("gatttool -I")
This returns the child process handle I can use. With...
child.sendline("connect {0}".format(DEVICE))
...I send the string to the gatttool (spawned process). The format member function is used to build the formatted string: “connect 00:32:40:08:00:12” as I would have it typed in.
Next, I need to wait for the connection. For this, I use
child.expect("Connection successful", timeout=5)
Which waits for the “Connection successful” string from the gatttool. I have specified that it should timeout after 5 seconds.
To read BLE characteristics, I use
child.sendline("char-read-hnd 0x30")
The handle 0x30 is for reading the accelerometer values. The gatttool would print something like this:
Characteristic value/descriptor: 02 00 00 00 a1 ff
I’m waiting for the first part of the output:
child.expect("Characteristic value/descriptor: ", timeout=10)
Then I wait for the end of the line:
child.expect("\r\n", timeout=10)
With child.before, I get the string just before the line end. For example...
child.before[0:5]
...will return “02 00” as substring (first 4 characters) from “02 00 00 00 a1 ff” string. That way, I get substrings of x, y and z accelerometer values.
To transform the hex string (in little endian) into a signed 16-bit number, I use the following Python sub-function:
# function to transform hex string like "0a cd" into signed integer
def hexStrToInt(hexstr):
val = int(hexstr[0:2],16) + (int(hexstr[3:5],16)<<8)
if ((val&0x8000)==0x8000): # treat signed 16bits
val = -((val^0xffff)+1)
return val
The Hexiwear's accelerometer values are ‘centi-float’ values. For example, the numerical value 123 would be 1.23. With this, I can print the x, y, and z values:
print(float(hexStrToInt(child.before[0:5]))/100),
print(float(hexStrToInt(child.before[6:11]))/100),
print(float(hexStrToInt(child.before[12:17]))/100)
Python Code to Read Accelerometer, Gyro, and Magnetometer
Here is the full source code of the code discussed above:
# Using Hexiwear with Python
import pexpect
import time
DEVICE = "00:32:40:08:00:12"
print("Hexiwear address:"),
print(DEVICE)
# Run gatttool interactively.
print("Run gatttool...")
child = pexpect.spawn("gatttool -I")
# Connect to the device.
print("Connecting to "),
print(DEVICE),
child.sendline("connect {0}".format(DEVICE))
child.expect("Connection successful", timeout=5)
print(" Connected!")
# function to transform hex string like "0a cd" into signed integer
def hexStrToInt(hexstr):
val = int(hexstr[0:2],16) + (int(hexstr[3:5],16)<<8)
if ((val&0x8000)==0x8000): # treat signed 16bits
val = -((val^0xffff)+1)
return val
#while True:
# Accelerometer
child.sendline("char-read-hnd 0x30")
child.expect("Characteristic value/descriptor: ", timeout=10)
child.expect("\r\n", timeout=10)
print("Accel: "),
print(child.before),
print(float(hexStrToInt(child.before[0:5]))/100),
print(float(hexStrToInt(child.before[6:11]))/100),
print(float(hexStrToInt(child.before[12:17]))/100)
# Accelerometer
child.sendline("char-read-hnd 0x34")
child.expect("Characteristic value/descriptor: ", timeout=10)
child.expect("\r\n", timeout=10)
print("Gyro: "),
print(child.before),
print(float(hexStrToInt(child.before[0:5]))/100),
print(float(hexStrToInt(child.before[6:11]))/100),
print(float(hexStrToInt(child.before[12:17]))/100)
# Magnetometer
child.sendline("char-read-hnd 0x38")
child.expect("Characteristic value/descriptor: ", timeout=10)
child.expect("\r\n", timeout=10)
print("Magneto:"),
print(child.before),
print(hexStrToInt(child.before[0:5])),
print(hexStrToInt(child.before[6:11])),
print(hexStrToInt(child.before[12:17]))
Save the script to a file (e.g. gatttool.py) and run it with:
python gatttool.py
This produces something like this:
Hexiwear address: 00:32:40:08:00:12
Run gatttool...
Connecting to 00:32:40:08:00:12 Connected!
Accel: 03 00 ff ff a1 ff 0.03 -0.01 -0.95
Gyro: 00 00 02 00 00 00 0.0 0.02 0.0
Magneto: b8 fc e2 04 c8 28 -840 1250 10440
Instead of printing the values, I can store them to a file or whatever I would like to do.
Python Script to Update Date/Time
Below is a Python script similar to the one above, which sets the Hexiwear's current date and time using the Unix time (seconds after 1970) from the Raspberry Pi:
# Python script to set the time on the Hexiwear
import pexpect
import time
from time import gmtime, strftime
print("---------------------")
print("Setting linux time")
print("local time: "),
print(time.ctime())
unixTime = int(time.time())
print("secs since 1970: "),
print(int(unixTime))
print("---------------------")
DEVICE = "00:32:40:08:00:12"
# Run gatttool interactively.
print("Running gatttool...")
child = pexpect.spawn("gatttool -I")
# Connect to the device.
print("Connecting to"),
print(DEVICE),
child.sendline("connect {0}".format(DEVICE))
child.expect("Connection successful", timeout=5)
print("Connected!")
# Write local time
command = "char-write-req 61 0304{0:02x}{1:02x}{2:02x}{3:02x}0000000000000000000000000000".format(unixTime&0xff, (unixTime>>8)&0xff, (unixTime>>16)&0xff, (unixTime>>24)&0xff)
print(command)
child.sendline(command)
child.expect("Characteristic value was written successfully", timeout=10)
print("done!")
And this is how it looks on the terminal:
Summary
Python is great for scripting things. With the pexpect Python class, I can spawn a process and then send and receive strings. I’m using this in my article to read sensor values from a BLE device connected to my Raspberry Pi.
Happy Pythoning!
Published at DZone with permission of Erich Styger. See the original article here.
Opinions expressed by DZone contributors are their own.

