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
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
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
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()