The Raspberry Pi 3 comes with BLE which can be used in a number of ways. The finished project at Holiday Lights and Music Festival With Love and Cheer uses BLE connected LED Lights and though a number of other things could be connected as well.

 

In this small post, I am going to add some details to the BLE python code for the project and allow the users to reuse the code as much as possible.

 

Starting off with BLE and Linux in Python

 

Notwithstanding the fact that there are libraries for both NodeJS as well as python for BLE, there are some other techniques that can be used to work with the interface. Take a look at the following script.

import pexpect
import time
 
LIGHT01 = "20:C3:8F:8D:8C:9E"
VALUE = ["00000000", "FF000000", "00FF0000", "0000FF00", "000000FF", "00000000"];
 
child = pexpect.spawn("gatttool -I")
 
child.sendline("connect {0}".format(LIGHT01))
child.expect("Connection successful", timeout=5)
print ("Connected to the light!")
while True:
    for i in range(6):
        child.sendline("char-write-req 0x0031 {0}".format(VALUE[i]))
        print ("Value: ", VALUE[i])
        child.expect("Characteristic value was written successfully", timeout=5)
        time.sleep(1);
 
child.sendline("disconnect")
 
child.close()
 
print ("Light Turned OFF")

 

It uses the gatttool in linux to control the same TI BLE Light and can be modified to talk to other peripherals such as the TI Sensor TAG. It is interesting to see how python can be used to wrap exiting utilities. I did a fairly detailed blog over at https://hackaday.com/2018/08/03/beginning-ble-experiments-and-making-everything-better/ but the idea is simple and can be used for other applications as well.

 

In the current project, I use the bluepy library and the code for the package is as follows

#!/usr/python
from bluepy import btle
from bluepy.btle import Scanner, DefaultDelegate
from struct import *

ble_light1 = "20:c3:8f:8d:c2:c0"
ble_light2 = "20:c3:8f:8d:8c:9e"

class ScanDelegate(DefaultDelegate):
    def __init__(self):
        DefaultDelegate.__init__(self)

    def handleDiscovery(self, dev, isNewDev, isNewData):
        if isNewDev:
            print "Discovered device", dev.addr
        elif isNewData:
            print "Received new data from", dev.addr

def scanForLights():
    result = 0; # 0=no lights, 1= light 1, 2= light 2, 3= both lights
    scanner = Scanner().withDelegate(ScanDelegate())
    devices = scanner.scan(3.0)
    for dev in devices:
        if dev.addr == ble_light1:
            print("Found Light 1")
            result = result | 0x01

        if dev.addr == ble_light2:
            print("Found Light 2")
            result = result | 0x02
    #     print "Device %s (%s), RSSI=%d dB" % (dev.addr, dev.addrType, dev.rssi)
    #     for (adtype, desc, value) in dev.getScanData():
    #         print "  %s = %s" % (desc, value)
    return result
    
def checkLights():
    p1 = btle.Peripheral(ble_light1)
    p2 = btle.Peripheral(ble_light2)
    
    v = pack("I", 0x00000000)
    
    svc = p1.getServiceByUUID("0000ffb0-0000-1000-8000-00805f9b34fb")
    h = svc.getCharacteristics()[4]
    p1.writeCharacteristic(h.valHandle, v, withResponse=True)
    p1.disconnect()
    
    svc = p2.getServiceByUUID("0000ffb0-0000-1000-8000-00805f9b34fb")
    h = svc.getCharacteristics()[4]
    p2.writeCharacteristic(h.valHandle, v, withResponse=True)
    p2.disconnect()

def writeLight(id, v):
    if id == 1:
        p = btle.Peripheral(ble_light1)
    elif id == 2:
        p = btle.Peripheral(ble_light2)
    
    svc = p.getServiceByUUID("0000ffb0-0000-1000-8000-00805f9b34fb")
    h = svc.getCharacteristics()[4]
    p.writeCharacteristic(h.valHandle, v, withResponse=True)
    p.disconnect()

def main():
    v = pack("I", 0x00000000)
    result = scanForLights()
    
    if result == 0:
        print("No light found")
    elif result == 1:
        writeLight(1, v)
    elif result == 2:
        writeLight(2, v)
    elif result == 3:
        writeLight(1, v)
        writeLight(2, v)

if __name__ == "__main__":
    main()

I divided the whole code into functions so that it may be reused once imported. There is a function to scan for the lights as well as connect to them and then write to them. Adding functions to read a particular characteristic should not be trivial and this code could be the base for the same.

 

If you feel like doing something with NodeJS, I encourage you to take a look at a similar writeup at https://hackaday.com/2018/08/24/how-to-mash-up-ble-nodejs-and-mqtt-to-get-internet-of-things/ . It uses the same TI LED Light though the code is structured very differently.

 

Moving to python was a personal choice since I intend to use it professionally. NodeJS is great if you are a web dev or have an Intel Board like the Edison leftover from the past.

 

Hope this is useful because it took me a while to figure out the difference between the two approaches.

 

Cheers.