Côté PC
Installation
$ sudo apt-get install python3-pip libglib2.0-dev
$ sudo pip3 install bluepy
Tests en lignes de commande
Vérification de l’adresse MAC
$ bluetoothctl
[bluetooth]# scan on
Discovery started
[CHG] Device 02:80:E1:00:00:AB RSSI: -89
[bluetooth]# exit
Test avec Gatttool
Gatttool est un utilitaire du driver Bluez
$ gatttool -b 02:80:E1:00:00:AB -I
[02:80:E1:00:00:AB][LE]> connect
Attempting to connect to 02:80:E1:00:00:AB
Connection successful
[02:80:E1:00:00:AB][LE]> primary
attr handle: 0x0001, end grp handle: 0x0004 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0005, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x0011 uuid: 0000ff10-0000-1000-8000-00805f9b34fb
attr handle: 0x0019, end grp handle: 0x001f uuid: 0000181a-0000-1000-8000-00805f9b34fb
[02:80:E1:00:00:AB][LE]> characteristics
handle: 0x0002, char properties: 0x20, char value handle: 0x0003, uuid: 00002a05-0000-1000-8000-00805f9b34fb
handle: 0x0006, char properties: 0x4e, char value handle: 0x0007, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0008, char properties: 0x4e, char value handle: 0x0009, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x000a, char properties: 0x0a, char value handle: 0x000b, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x000d, char properties: 0x0c, char value handle: 0x000e, uuid: 0000ff12-0000-1000-8000-00805f9b34fb
handle: 0x000f, char properties: 0x12, char value handle: 0x0010, uuid: 0000ff11-0000-1000-8000-00805f9b34fb
handle: 0x001a, char properties: 0x12, char value handle: 0x001b, uuid: 00002a6e-0000-1000-8000-00805f9b34fb
handle: 0x001d, char properties: 0x12, char value handle: 0x001e, uuid: 00002a6d-0000-1000-8000-00805f9b34fb
[02:80:E1:00:00:AB][LE]> char-write-cmd 0x000e 00 # Switch Off Led
[02:80:E1:00:00:AB][LE]> char-write-cmd 0x000e 01 # Switch On led
[02:80:E1:00:00:AB][LE]> char-write-cmd 0x001c 01 # Start Temp and Pressure Measurements
[02:80:E1:00:00:AB][LE]> char-read-hnd 0x001b # Read Temperature Char
Characteristic value/descriptor: d3 00
[02:80:E1:00:00:AB][LE]> char-read-hnd 0x001e # Read Pressure Char
Characteristic value/descriptor: d6 8d 01 00
IHM en Python
|
|
bleiotEnib.py
#! /usr/bin/python3
#=======================================================================
# $ ./bleiotEnib.py 02:80:e1:00:00:ab
#=======================================================================
from bluepy.btle import UUID, Peripheral, ADDR_TYPE_PUBLIC, DefaultDelegate
from tkinter import *
import argparse
import time
import struct
import binascii
#=======================================================================
def STM32_UUID(val):
return UUID("0000%04X-0000-1000-8000-00805F9B34FB" % val)
ENVIRONMENT_SERVICE_UUID = 0x181A
E_PRESSION_CHAR_UUID = 0x2A6D
E_TEMPERATURE_CHAR_UUID = 0x2A6E
#E_HUMIDITY_CHAR_UUID = 0x2A6F
LED_SERVICE_UUID = 0xFF10
LEDSTATE_CHAR_UUID = 0xFF11
LEDSWITCH_CHAR_UUID = 0xFF12
CCCD_UUID = 0x2902
e_temperature_handle = None
e_pression_handle = None
m_tap_handle = None
ledswitch_handle = None
ledstate_handle = None
ledstate = 0
data_temperature=0
data_state=0
data_pression=0
#=======================================================================
# LED Service
#=======================================================================
class LedService():
serviceUUID = STM32_UUID(LED_SERVICE_UUID )
ledswitch_char_uuid = STM32_UUID(LEDSWITCH_CHAR_UUID)
ledstate_char_uuid = STM32_UUID(LEDSTATE_CHAR_UUID)
def __init__(self, periph):
self.periph = periph
self.led_service = None
self.ledswitch_char = None
self.ledswitch_cccd = None
self.ledstate_char = None
self.ledstate_cccd = None
def enable(self):
""" Enables the class by finding the service and its characteristics. """
global ledswitch_handle
global ledstate_handle
if self.led_service is None:
self.led_service = self.periph.getServiceByUUID(self.serviceUUID)
if self.ledswitch_char is None:
self.ledswitch_char = self.led_service.getCharacteristics(self.ledswitch_char_uuid)[0]
ledswitch_handle = self.ledswitch_char.getHandle()
if self.ledstate_char is None:
self.ledstate_char = self.led_service.getCharacteristics(self.ledstate_char_uuid)[0]
ledstate_handle = self.ledstate_char.getHandle()
self.ledstate_cccd = self.ledstate_char.getDescriptors(forUUID=CCCD_UUID)[0]
def set_ledswitch_notification(self, state):
if self.ledswitch_cccd is not None:
if state == True:
self.ledswitch_cccd.write(b"\x01\x00", True)
else:
self.ledswitch_cccd.write(b"\x00\x00", True)
def set_ledstate_notification(self, state):
if self.ledstate_cccd is not None:
if state == True:
self.ledstate_cccd.write(b"\x01\x00", True)
else:
self.ledstate_cccd.write(b"\x00\x00", True)
def set_switch_led_on(self):
self.ledswitch_char.write(b"\x01", True)
def set_switch_led_off(self):
self.ledswitch_char.write(b"\x00", True)
def disable(self):
set_ledswitch_notification(False)
set_ledstate_notification(False)
#=======================================================================
# Environment Service Class
#=======================================================================
class EnvironmentService():
serviceUUID = STM32_UUID(ENVIRONMENT_SERVICE_UUID)
temperature_char_uuid = STM32_UUID(E_TEMPERATURE_CHAR_UUID)
pression_char_uuid = STM32_UUID(E_PRESSION_CHAR_UUID)
def __init__(self, periph):
self.periph = periph
self.environment_service = None
self.temperature_char = None
self.temperature_cccd = None
self.pression_char = None
self.pression_cccd = None
def enable(self):
""" Enables the class by finding the service and its characteristics. """
global e_temperature_handle
global e_pression_handle
if self.environment_service is None:
self.environment_service = self.periph.getServiceByUUID(self.serviceUUID)
if self.temperature_char is None:
self.temperature_char = self.environment_service.getCharacteristics(self.temperature_char_uuid)[0]
e_temperature_handle = self.temperature_char.getHandle()
self.temperature_cccd = self.temperature_char.getDescriptors(forUUID=CCCD_UUID)[0]
if self.pression_char is None:
self.pression_char = self.environment_service.getCharacteristics(self.pression_char_uuid)[0]
e_pression_handle = self.pression_char.getHandle()
self.pression_cccd = self.pression_char.getDescriptors(forUUID=CCCD_UUID)[0]
def set_temperature_notification(self, state):
if self.temperature_cccd is not None:
if state == True:
print("temperature write")
self.temperature_cccd.write(b"\x01\x00", True)
else:
self.temperature_cccd.write(b"\x00\x00", True)
def set_pression_notification(self, state):
if self.pression_cccd is not None:
if state == True:
print("pression write")
self.pression_cccd.write(b"\x01\x00", True)
else:
self.pression_cccd.write(b"\x00\x00", True)
def disable(self):
set_temperature_notification(False)
set_pression_notification(False)
#=======================================================================
# MyDelegate Class
#=======================================================================
class MyDelegate(DefaultDelegate):
def handleNotification(self, hnd, data):
global data_pression,data_temperature, data_state
if (hnd == e_temperature_handle):
concat_dat = binascii.b2a_hex(data[::-1]) # [::-1] reverse the string
temp_f = float(int(concat_dat,16))/10
print("Temp received:" + str(temp_f))
data_temperature = temp_f
elif (hnd == e_pression_handle):
concat_dat = binascii.b2a_hex(data[::-1])
pression_f = float(int(concat_dat,16))/100
print("Pression received:" + str(pression_f))
data_pression = pression_f
elif (hnd == ledstate_handle):
data_state = data
#=======================================================================
# Bleiot Class
#=======================================================================
class Bleiot(Peripheral):
"""
Bleiot module. Instance the class and enable to get access to the Bleiot Sensors.
The addr of your device has to be know, or can be found by using the hcitool command line
tool, for example. Call "> sudo hcitool lescan" and your bleiot's address should show up.
"""
def __init__(self, addr):
Peripheral.__init__(self, addr, addrType=ADDR_TYPE_PUBLIC)
self.environment = EnvironmentService(self)
self.led = LedService(self)
#=======================================================================
# Functions
#=======================================================================
def askFordatas():
bleiot.waitForNotifications(args.t)
strTemperature.set(str(data_temperature) + ' °C')
strPression.set(str(data_pression) + ' hPa')
strLedState.set(str(data_state) + ' --- ' + time.ctime())
ui.after(1,askFordatas)
def onPushSwitch():
global ledstate
if ledstate == 0:
print("switch on")
bleiot.led.set_switch_led_on()
ledstate = 1
else:
print("switch off")
bleiot.led.set_switch_led_off()
ledstate = 0
#=======================================================================
# Main Function
#=======================================================================
if __name__ == "__main__" :
parser = argparse.ArgumentParser()
parser.add_argument('mac_address', action='store', help='MAC address of BLE peripheral')
parser.add_argument('-n', action='store', dest='count', default=0, type=int, help="Number of times to loop data")
parser.add_argument('-t',action='store',type=float, default=0.1, help='time between polling')
args = parser.parse_args()
print('Connecting to ' + args.mac_address)
bleiot = Bleiot(args.mac_address)
print('Connected...')
bleiot.setDelegate(MyDelegate())
print('Enabling selected sensors...')
bleiot.environment.enable()
bleiot.environment.set_temperature_notification(True)
bleiot.environment.enable()
bleiot.environment.set_pression_notification(True)
bleiot.led.enable()
bleiot.led.set_ledstate_notification(True)
print('All requested sensors and notifications are enabled...')
time.sleep(1.0)
#-------------------------------------------------------------------
ui=Tk()
ui.title("BLEIOT")
ui.geometry("200x200")
labelTemperature=Label(ui, text="Temperature", font=("Arial", 10), fg="black")
labelTemperature.pack()
strTemperature = StringVar()
TemperatureEntry=Entry(ui, textvariable=strTemperature)
TemperatureEntry.pack()
labelPression=Label(ui, text="Pression", font=("Arial", 10), fg="black")
labelPression.pack()
strPression=StringVar()
PressionEntry=Entry(ui, textvariable=strPression)
PressionEntry.pack()
switchButton=Button(ui, text="SWITCH LED", font=("Arial",10, "bold"), bg="seagreen3", fg="black", bd=3, relief=RAISED, command=onPushSwitch)
switchButton.pack()
strLedState=StringVar()
strLedEntry=Entry(ui, textvariable=strLedState)
strLedEntry.pack()
ui.after(1,askFordatas)
ui.mainloop()
#=======================================================================
Interface en C
Installation
test
$ ./bleiotEnib 02:80:e1:00:00:ab
switch led handle = 14
state led handle = 16
temperature handle = 27
pressure handle = 30
Notification uuid = fb349b5f-8000-0080-0010-00006e2a0000 value: 1980
Notification uuid = fb349b5f-8000-0080-0010-00006e2a0000 value: 23814110
Notification uuid = fb349b5f-8000-0080-0010-00006e2a0000 value: 1980
Notification uuid = fb349b5f-8000-0080-0010-00006e2a0000 value: 23814110
Notification uuid = fb349b5f-8000-0080-0010-00006e2a0000 value: 1980
...
bleiotEnib.c
bleiotEnib.c
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include "gattlib.h"
#define ENV_CHAR_PRESSURE "00002a6d-0000-1000-8000-00805f9b34fb"
#define ENV_CHAR_TEMPERATURE "00002a6e-0000-1000-8000-00805f9b34fb"
#define LED_CHAR_SWITCH "0000ff12-0000-1000-8000-00805f9b34fb"
#define LED_CHAR_STATE "0000ff11-0000-1000-8000-00805f9b34fb"
gatt_connection_t* m_connection;
static int opt_handle = -1;
char buffer[10];
uuid_t env_char_temperature_uuid;
uuid_t env_char_pressure_uuid;
uuid_t led_char_switch_uuid;
uuid_t led_char_state_uuid;
uuid_t g_uuid;
//======================================================================
void notification_cb(const uuid_t* uuid, const uint8_t* data, size_t data_length, void* user_data) {
char uuid_str[MAX_LEN_UUID_STR + 1];
int i;
gattlib_uuid_to_string(uuid, uuid_str, MAX_LEN_UUID_STR + 1);
printf("Notification uuid = %s value: ", uuid_str);
for (i = 0; i < data_length; i++) {
printf("%d", data[i]);
}
printf("\n");
}
//======================================================================
static void usage(char *argv[]) {
printf("%s <device_address>\n", argv[0]);
}
//======================================================================
void int_handler(int dummy) {
gattlib_disconnect(m_connection);
exit(0);
}
//======================================================================
gatt_read_cb_t read_cb(void) {
}
//======================================================================
int main(int argc, char *argv[]) {
char input[256];
char* input_ptr;
uint16_t temperature_handle = 0, pressure_handle = 0, switchLed_handle = 0, stateLed_handle=0;
int i, ret, total_length, length = 0;
void* adapter;
if (argc != 2) {
usage(argv);
return 1;
}
ret = gattlib_adapter_open(NULL, &adapter);
if (ret) {
fprintf(stderr, "ERROR: Failed to open adapter.\n");
return 1;
}
m_connection = gattlib_connect(adapter, argv[1], BDADDR_LE_PUBLIC, BT_SEC_LOW, 0, 0);
if (m_connection == NULL) {
fprintf(stderr, "Fail to connect to the bluetooth device.\n");
return 1;
}
// Convert characteristics to their respective UUIDs
ret = gattlib_string_to_uuid(ENV_CHAR_TEMPERATURE, strlen(ENV_CHAR_TEMPERATURE) + 1, &env_char_temperature_uuid);
ret = gattlib_string_to_uuid(ENV_CHAR_PRESSURE, strlen(ENV_CHAR_PRESSURE) + 1, &env_char_pressure_uuid);
ret = gattlib_string_to_uuid(LED_CHAR_SWITCH, strlen(LED_CHAR_SWITCH) + 1, &led_char_switch_uuid);
ret = gattlib_string_to_uuid(LED_CHAR_STATE, strlen(LED_CHAR_STATE) + 1, &led_char_state_uuid);
// Look for handle for CHARACTERISTIC_UUID
gattlib_characteristic_t* characteristics;
int characteristic_count;
ret = gattlib_discover_char(m_connection, &characteristics, &characteristic_count);
if (ret) {
fprintf(stderr, "Fail to discover characteristic.\n");
return 1;
}
for (i = 0; i < characteristic_count; i++) {
if (gattlib_uuid_cmp(&characteristics[i].uuid, &env_char_temperature_uuid) == 0)
{
temperature_handle = characteristics[i].value_handle;
printf("temperature handle = %d \n", temperature_handle);
}
else if (gattlib_uuid_cmp(&characteristics[i].uuid, &env_char_pressure_uuid) == 0)
{
pressure_handle = characteristics[i].value_handle;
printf("pressure handle = %d \n", pressure_handle);
}
else if (gattlib_uuid_cmp(&characteristics[i].uuid, &led_char_switch_uuid) == 0)
{
switchLed_handle = characteristics[i].value_handle;
printf("switch led handle = %d \n", switchLed_handle);
}
else if (gattlib_uuid_cmp(&characteristics[i].uuid, &led_char_state_uuid) == 0)
{
stateLed_handle = characteristics[i].value_handle;
printf("state led handle = %d \n", stateLed_handle);
}
}
free(characteristics);
// Enable Status Notification
uint16_t enable_notification = 0x0001;
gattlib_write_char_by_handle(m_connection, temperature_handle + 1, &enable_notification, sizeof(enable_notification));
sleep(1);
gattlib_write_char_by_handle(m_connection, pressure_handle + 1, &enable_notification, sizeof(enable_notification));
sleep(1);
gattlib_write_char_by_handle(m_connection, stateLed_handle +1, &enable_notification, sizeof(enable_notification));
sleep(1);
// Register notification handler
gattlib_register_notification(m_connection, notification_cb, NULL);
signal(SIGINT, int_handler); // Register handler to catch Ctrl+C
while(1) {
/*enable_notification = 0x0001;
gattlib_write_char_by_handle(m_connection, switchLed_handle + 1, &enable_notification, sizeof(enable_notification));
sleep(1);
enable_notification = 0x0000;
gattlib_write_char_by_handle(m_connection,switchLed_handle + 1, &enable_notification, sizeof(enable_notification));
sleep(1);
*/
}
return 0;
}
//======================================================================