Introduction: Pressure and Temperature Monitoring

Le but de ce projet est de faire communiquer via bluetooth un module BLE equipé de capteurs de pression et température avec une raspberry pi qui sera en charge de mettre les données recueilli en ligne.

Nous allons nous laisser la possibilité de recueillir les données depuis 2 différents capteur tout deux connecté en BLE à la raspberry Pi.

Liste du matériel nécessaire :

  • Raspberry pi avec une connectivité bluetooth fonctionnel (Dongle ou intégré)
  • Sensortag Low Energy Bluetooth equipé d'un capteur de température (dans notre cas un T.I. SensorTag CC2541 )
  • Un capteur de Température/pression (BMP180)

  • Un shield sur lequel connecter le capteur (Grove Base Shield )

  • Une Carte Redbearlab nRF51822 sur laquel nous allons connecter le shield.

Step 1: Une Première Approche Avec Le Sensor Tag

Dans un premier temps il faudra installer bluez ainsi qu’un environnement de développement python fonctionnel et le paquet python pexpect permettant d’éxecuter du code shell depuis le code Python.

Bluez est un driver BLE qui nous permettra de communiquer avec le Sensortag.

Une fois l’environnement mis en place il faudra scanner les différents device BLE à porté de la Raspberry via la commande ci-après. Cette commande renverra le nom ainsi que la mac adresse de chaque device à porté. Il faudra copier coller l'adresse mac du Sensortag.

Copier coller le script python ci dessous,

http://www.doritique.fr/Articles/View_Article.php?...

Modifier la variable ble_addr du script python par la mac adresse du sensor tag obtenue précédemment.

Lancer le script Pyhton, qui affichera les valeur de température lu par le sensor tag.

# Installation de l'environnement
sudo apt-get install bluez 
sudo apt-get install python
sudo apt-get install python-pexpect

# Scan des devices BLE à porté
hcitool lescan

Step 2: Connection Du Matériel

Dans un premier temps nous allons connecter le shield à la bearboard
puis le capteur au shield sur l’entrée I2C. Il ne faudra pas oublier de passer le switch contrôlant le voltage du shield sur 3,3 volts.

Step 3: Configuration De La Redbearlab

Il faut dans un premier temps s’inscrire sur embed

https://developer.mbed.org

Une fois inscrit il faudra importer un projet existant nommer “nRF51822_SimpleControls” et lancer le projet

L'interface de programmation offerte par mbed nous permet de compiler le code et de télécharger le binaire issu de la compilation du code.

Pour utiliser ce binaire il suffira de connecter la Readbearlab via usb sur l'ordinateur et de copier dessus le binaire.

Step 4: Exploitation Du BMP180

Pour lire les valeurs capté par le BMP 180 il faut modifier le projet précédemment importé. Il faut a faire un include BMP085.h qui est le header correspondant à la classe contenant les méthodes propre à notre capteur.

Le code est composé de 2 fonctions principal:

  • WrittenHandler: Lit le buffer envoyé par la Raspberry au RedBearLab afin de setter un booléen permettant de savoir quel module est solicité par la Raspberry
  • m_status_check_handle: Cette fonction est appelé périodiquement, elle verifier si une demande de relevé a été faite au capteur si oui elle envoi la valeur lu par le capteur à la Raspberry via la la méthode updateCharacteristicValue

La périodicité d'appelle à la fonction m_status_check_handle est réglé par l'objet ticker grâce à la méthode attach_us.


#include "mbed.h"
#include "ble/BLE.h"
#include "ble/FunctionPointerWithContext.h"
#include "Servo.h"
#include "GattCallbackParamTypes.h"
#include "BMP085.h"</p><p>#define BLE_UUID_TXRX_SERVICE            0x0000 /**< The UUID of the Nordic UART Service. */
#define BLE_UUID_TX_CHARACTERISTIC       0x0002 /**< The UUID of the TX Characteristic. */
#define BLE_UUIDS_RX_CHARACTERISTIC      0x0003 /**< The UUID of the RX Characteristic. */

#define TXRX_BUF_LEN                     20
#define DIGITAL_OUT_PIN                  P0_17  //D7
#define DIGITAL_IN_PIN                   P0_5   //A4
#define PWM_PIN                          P0_16  //D6
#define SERVO_PIN                        P0_14  //D10
#define ANALOG_IN_PIN                    P0_1   //A0

BLE             ble;
DigitalOut      LED_SET(DIGITAL_OUT_PIN);
DigitalIn       BUTTON(DIGITAL_IN_PIN);
PwmOut          PWM(PWM_PIN);
AnalogIn        ANALOG(ANALOG_IN_PIN);
Servo           MYSERVO(SERVO_PIN);
BMP085  myCaptor(P0_29, P0_28);
Serial pc(USBTX, USBRX);
static uint8_t analog_enabled = 0;
static uint8_t captor_enabled = 0;
static uint8_t captor_enabled_for_pressure = 0;

// The Nordic UART Service
static const uint8_t uart_base_uuid[] = {0x71, 0x3D, 0, 0, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_tx_uuid[]   = {0x71, 0x3D, 0, 3, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_rx_uuid[]   = {0x71, 0x3D, 0, 2, 0x50, 0x3E, 0x4C, 0x75, 0xBA, 0x94, 0x31, 0x48, 0xF1, 0x8D, 0x94, 0x1E};
static const uint8_t uart_base_uuid_rev[] = {0x1E, 0x94, 0x8D, 0xF1, 0x48, 0x31, 0x94, 0xBA, 0x75, 0x4C, 0x3E, 0x50, 0, 0, 0x3D, 0x71};</p><p>uint8_t txPayload[TXRX_BUF_LEN] = {0,};
uint8_t rxPayload[TXRX_BUF_LEN] = {0,};

GattCharacteristic  txCharacteristic(uart_tx_uuid, txPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
                                      
GattCharacteristic  rxCharacteristic(uart_rx_uuid, rxPayload, 1, TXRX_BUF_LEN, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
                                      
GattCharacteristic *uartChars[] = {&txCharacteristic, &rxCharacteristic};

GattService         uartService(uart_base_uuid, uartChars, sizeof(uartChars) / sizeof(GattCharacteristic *));

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    pc.printf("Disconnected \r\n");
    pc.printf("Restart advertising \r\n");
    ble.startAdvertising();
}
void confirmationHandler(uint16_t  Handler)
{
    if (captor_enabled)
        captor_enabled = false;
}
void WrittenHandler(const GattWriteCallbackParams *Handler)
{   
    uint8_t buf[TXRX_BUF_LEN];
    uint16_t bytesRead, index;
    
    if (Handler->handle == txCharacteristic.getValueAttribute().getHandle()) 
    {
        ble.readCharacteristicValue(txCharacteristic.getValueAttribute().getHandle(), buf, &bytesRead);
        memset(txPayload, 0, TXRX_BUF_LEN);
        memcpy(txPayload, buf, TXRX_BUF_LEN);       
        
        for(index=0; index<bytesread; index++)="" pc.putc(buf[index]);="" if(buf[0]="=" 0x01)="" {="" if(buf[1]="=" 0x02)="" while(1)="" led_set="!LED_SET;" wait(0.25);="" }="" else="" 0xa0)="" analog_enabled="1;" captor_enabled="1;" 0x03)="" captor_enabled_for_pressure="1;" float="" value="(float)buf[1]/255;" pwm="value;" }<="" p=""></bytesread;></p><p>void m_status_check_handle(void)
{   
    uint8_t buf[4];
    if (analog_enabled)  // if analog reading enabled
    {
        // Read and send out
        float s = ANALOG;
        uint16_t value = s*1024; 
        buf[0] = (0x0B);
        buf[1] = (value >> 8);
        buf[2] = (value);
        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 3); 
    }
    if (captor_enabled)  // if analog reading enabled
    {
        // Read and send out
        captor_enabled = false;
        myCaptor.update();
        float s = myCaptor.get_temperature() * 100;
        int value = s; 
        buf[0] = (value >> 24);
        buf[1] = (value >> 16);
        buf[2] = (value >> 8);
        buf[3] = value;
        //for(int i = 0; i < 200000; ++i)
        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4); 
    }
    // add to get pressure
    if (captor_enabled_for_pressure)
    {
        // Read and send out
        captor_enabled_for_pressure = false;
        myCaptor.update();
        float s = myCaptor.get_pressure() * 100;
        uint32_t value = s; 
        buf[0] = (value >> 24);
        buf[1] = (value >> 16);
        buf[2] = (value >> 8);
        buf[3] = value;
        ble.updateCharacteristicValue(rxCharacteristic.getValueAttribute().getHandle(), buf, 4); 
    }
}</p><p>int main(void)
{   
    Ticker ticker;
    ticker.attach_us(m_status_check_handle, 200000);
    
    ble.init();
    ble.onDisconnection(disconnectionCallback);
    ble.onDataWritten(WrittenHandler);
    ble.onConfirmationReceived(confirmationHandler);
    pc.baud(9600);
    pc.printf("SimpleChat Init \r\n");
    
    // setup advertising 
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                    (const uint8_t *)"Mustafa", sizeof("Mustafa") - 1);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
                                    (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid));
    // 100ms; in multiples of 0.625ms. 
    ble.setAdvertisingInterval(160);

    ble.addService(uartService);
    
    ble.startAdvertising(); 
    
    pc.printf("Advertising Start \r\n");
    
    while(1)
    {
        ble.waitForEvent(); 
    }
}

Step 5: Relevé Des Données Depuis La Raspberry

Il faudra scanner les différents device BLE à porté de la Raspberry via la commande ci-après. Cette commande renverra le nom ainsi que la mac adresse de chaque device à porté. Il faudra copier coller l'adresse mac du RedBearLab.

Copier coller le script python ci dessous,

http://www.doritique.fr/Articles/View_Article.php?...

Modifier la variable ble_addr du script python par la mac adresse du RedBearLab obtenue précédemment.

Il faudra aussi modifier le script python comme ci-dessous afin qu'il envoi le buffer de requête attendu par la ReadBearLab et correspondant au capteur dont on veut récupérer les données.

import os
import sys
import pexpect
import time
import urllib2
import urllib

ble_addr="E5:AE:C1:71:96:E4"
class Sensortag:
   
  def __init__(self,ble_addr):
    self.ble_addr=ble_addr
    self.child = pexpect.spawn('gatttool -t random -b ' + ble_addr + ' -I')
    self.child.expect('\[LE\]>')
    print("Try to connect to the board")
    self.child.sendline('connect')
    self.child.expect('Connection successful')
    print("Connected")
    return
	

  def getTemperature(self):
    print("try to update the temperature")

    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    self.child.sendline('char-write-cmd 0x000e A00100')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    print("temperature: " + str(int(rval[7], 16)))
    return int(rval[7], 16)

 def getPressure(self):
    print("try to update the pressure")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    self.child.sendline('char-write-cmd 0x000e A00300')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    pressure = "" + rval[6] + rval[7]
    print("pressure: " + str(int(pressure, 16)))
    return int(pressure, 16)

  def exit(self):
    self.child.sendline('exit');
    return

def main(): 
  sensortag=Sensortag(ble_addr)
  while True:
    tmpIR=sensortag.getTemperature()
    prsIR=sensortag.getPressure()
    time.sleep(3)
  sensortag.exit();
    #time.sleep(10)


if __name__ == "__main__":
    main()

Step 6: Mise En Place Du Serveur Web Et De Php

Afin d'afficher les donner mesurées sur une page web il nous faut mettre un place un serveur web sur la Raspberry, ce serveur sera en charge de d'heberger notre page web.

Pour ceux nous allons installer un serveur apache2 et tester son installation via les commande suivante :

sudo aptitude upgrade
sudo aptitude install apache2
sudo chown -R www-data:pi /var/www/html/
sudo chmod -R 770 /var/www/html/
wget -O verif_apache.html href="http://127.0.0.1" rel="nofollow"  http://127.0.0.1  
cat ./verif_apache.html | grep "It works!"

Si vous voyez s'afficher "It works!" en réponse à la derniere commande alors le serveurs est bien installé et fonctionnel.

Pour installer php5 il suffira de faire la commande suivante:

sudo aptitude install php5

Step 7: Site Web Statique

Il faut d'abord modifier le script pyhton afin qu'en plus d'afficher les résultats sur la console standard il puisse être écrit vers un fichier.

import urllib2
import urllib
ble_addr="E5:AE:C1:71:96:E4"
class Sensortag:
def __init__(self,ble_addr):
    self.ble_addr=ble_addr
    self.child = pexpect.spawn('gatttool -t random -b ' + ble_addr + ' -I')
    self.child.expect('\[LE\]>')
    print("Try to connect to the board")
    self.child.sendline('connect')
    self.child.expect('Connection successful')
    print("Connected")
    return
  def getTemperature(self):
    print("try to update the temperature")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    print("wait line")
    self.child.sendline('char-write-cmd 0x000e A00100')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    temperature = int(rval[7], 16)
    print(temperature)
    return temperature

def getPressure(self):
    print("try to update the pressure")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    self.child.sendline('char-write-cmd 0x000e A00300')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    pressure = "" + rval[6] + rval[7]
    print("pressure: " + str(int(pressure, 16)))
    return int(pressure,16)

def exit(self):
    self.child.sendline('exit');
    return

def main():
  sensortag=Sensortag(ble_addr)
  i = 0
  while i < 50:
    aux = datetime.now().strftime("%Y-%m-%d %H:%M:%S") +" " + str(sensortag.getTemperature()) + " "+ str(sensortag.getPressure())
    fo = open("test.txt", "a")
    fo.write(aux + '\r\n');
    time.sleep(10)
    i -= 1
  sensortag.exit();
if __name__ == "__main__":
    main()

Il faut maintenant mettre sur le serveur apache le code html/php de la page web statique, ce code doit être placé dans le répertoire /var/www/html sous le nom index.php

Maintenant on peut voir le site web s'afficher en se connectant depuis un navigateur à l'adresse IP de la Raspberry.


Step 8: Utilisation D'orbidot/ubidot

Nous allons maintenant mettre nos données sur un serveur participatif permettant a tout à chacun de partager ses données de températures et de pression capter.

Se rendre sur la page ci-dessous et s'inscrire

http://ubidots.com

Une fois l'inscription terminée il faudra suivre le tutoriel proposé par ubidots.

Nous devrons donc modifier le script python de façon à ce qu'il communique les données relevées.

Pour ceux dans le code ci- dessous il faudra écrire son token d'accès à la place de 'YOUR ACCESS TOKEN'

from ubidots import ApiClient
import math
import time
import os
import sys
import pexpect
import time
import urllib2
import urllib
ble_addr="E5:AE:C1:71:96:E4"


class Sensortag:

def __init__(self,ble_addr):
    self.ble_addr=ble_addr
    self.child = pexpect.spawn('gatttool -t random -b ' + ble_addr + ' -I')
    self.child.expect('\[LE\]>')
    print("Try to connect to the board")
    self.child.sendline('connect')
    self.child.expect('Connection successful')
    print("Connected")
    return


  def getTemperature(self):
    print("try to update the temperature")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    print("wait line")
    self.child.sendline('char-write-cmd 0x000e A00100')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    temperature = int(rval[7], 16)
    print(temperature)
    return temperature

def getPressure(self):
    print("try to update the pressure")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    self.child.sendline('char-write-cmd 0x000e A00300')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    pressure = "" + rval[6] + rval[7]
    print("pressure: " + str(int(pressure, 16)))
    return int(pressure,16)


def exit(self):
    self.child.sendline('exit');
    return

def main():
  api = ApiClient(token='YOUR ACCESS TOKEN')
  variable = api.get_variable('574b8722762542450b077fa1')
  sensortag=Sensortag(ble_addr)
  i = 0
  while i < 50:
    response = variable.save_value({"value": sensortag.getTemperature()})
    print response
    time.sleep(10)
    i -= 1
sensortag.exit();

if __name__ == "__main__":
    main()

Step 9: Mise En Place D'une Base De Donnée De Relevée

Afin de sauvegarder les différentes valeurs captés nous allons les stocker dans une base de données mySQL.

Il faut tout d'abord installé mySQL:

sudo apt-get install mysql

Pour initialiser la base de données "iot" il faudra faire les commandes suivantes

mysql -u root -p CREATE DATABASE iot
USE iot
\. init.sql

Attachments

Step 10: Enregistrement Vers La Base De Donnée

Pour sauvegarder les valeurs captés il faut à nouveau modifier le script python

import _mysql from datetime import date, datetime, timedelta
import os
import sys
import pexpect
import time
import urllib2
import urllib
ble_addr="E5:AE:C1:71:96:E4"
class Sensortag:
   
  def __init__(self,ble_addr):
    self.ble_addr=ble_addr
    self.child = pexpect.spawn('gatttool -t random -b ' + ble_addr + ' -I')
    self.child.expect('\[LE\]>')
    print("Try to connect to the board")
    self.child.sendline('connect')
    self.child.expect('Connection successful')
    print("Connected")
    return
	
  def getTemperature(self):
    print("try to update the temperature")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    print("wait line")
    self.child.sendline('char-write-cmd 0x000e A00100')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    temperature = int(rval[7], 16)
    print(temperature)
    return temperature
  def getPressure(self):
    print("try to update the pressure")
    self.child.sendline('char-write-req 0x0011 0100 -listen')
    self.child.expect('Characteristic value was written successfully')
    self.child.sendline('char-write-cmd 0x000e A00300')
    self.child.expect('Notification handle = 0x0010 value: 0b .*')
    rval = self.child.after.split()
    pressure = "" + rval[6] + rval[7]
    print("pressure: " + str(int(pressure, 16)))
    return int(pressure, 16) 
  def exit(self):
    self.child.sendline('exit');
    return

def main():
  db=_mysql.connect(host="localhost",user="root",
                              passwd="raspberry",db="iot")
  sensortag=Sensortag(ble_addr)
  i = 0
  while i < 50:
    aux=("INSERT INTO Temperature(time, temp, pressure)"
            " VALUE (\""+datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            +"\", "+str(sensortag.getTemperature())+ ", " 
            +str(sensortag.getPressure()) + ")")
    print(aux)
    db.query(aux)
    time.sleep(10)
    i -= 1
  sensortag.exit();

if __name__ == "__main__":
    main()