TI Sensortag : Transmission des données et fiabilisation du script (partie 3)

20 aout 2014 rdorigny 0 commentaires

Maintenant que nous sommes capable de récupérer les données, il est temps de voir comment les transmettre et les stocker.

Autre problématique que nous verrons, fiabiliser et pérenniser le script, l'objectif étant de l'oublier et surtout de ne pas être contraint d'intervenir toutes les cinq minutes pour causes de plantages intempestifs...




1)Transmission et stockage des données

L'idée consiste à envoyer une requête web comme http://monsite.fr/script.php?tp=12.5&hum=65.3&pr=1008.9&sonde=1 avec les données mesurées sur un script PHP. Le script se chargera de récupérer les données et de les enregistrer dans une base de données. Si vous avez un hébergeur comme OVH ou 1and1, vous pouvez utiliser votre hébergement pour stocker vos données dans le cloud.

Pour le script php, rien d'extraordinaire:
<?php //réaliser la connexion à la base de données au préalable if (isset($_GET["tp"])) { $tp=$_GET["tp"]; print("La température reçue :".$tp."<BR>"); } if (isset($_GET["hum"])) { $hum=$_GET["hum"]; print("L'humidité reçue :".$hum."<BR>"); } if (isset($_GET["pr"])) { $pr=$_GET["pr"]; print("La pression reçue :".$pr."<BR>"); } if (isset($_GET["sonde"])) { $sonde=$_GET["sonde"]; print("Le numéro de la sonde :".$sonde."<BR>"); } //Insertion ds la base de l'enregistrement réceptionné $date=date('d m Y H:i:s'); print("Date :".$date."<BR>"); $requete="INSERT INTO matable (sonde,date,pr,tp,hum) VALUES (".$sonde.",'".$date."',".$pr.",".$tp.",".$hum.")"; print("requête :".$requete."<BR>"); $resultat=mysql_query($requete,$Connection); print("resultat :".$resultat."<BR>"); ?>

OK pour la réception, mais comment faire pour envoyer la requête web automatiquement? C'est là que le langage python est puissant, car c'est une affaire traitée en deux lignes de code! Rien à voir avec les 20 lignes que j'aurais eu en C. Et cela grâce au module urllib et urllib2. Donc voici la fonction que j'ai créé pour envoyer notre requête.
import urllib import urllib2 #Fonction chargee de la transmission des donnees def sendval(temp,hum,pres): data={} data['tp']='{:.2f}'.format(temp) data['hum']='{:.2f}'.format(hum) data['pr']='{:.2f}'.format(pres) data['sonde']='1' url_values=urllib.urlencode(data) #print(url_values) data=urllib2.urlopen("http://monsite.fr/script.php"+"?"+url_values) #print("transmission OK")

2)Fiabilisation du script

Tout d'abord, il faut faire tourner le script en tâche de fond sur notre machine Linux. Pour cela, l'idéal serait de le transformer en daemon. Python propose plusieurs méthodes, j'ai choisi la plus connue :
#Mise en daemon fpid = os.fork() if fpid!=0: # Fonctionne en daemon desormais. Le PID est fpid sys.exit(0)

A vrai dire, j'ai lancé le script et il a bien fonctionné durant 3 jours. Mais une coupure réseau l'a fait planter!! Et patatra, arrêt des mesures... Bref, pas terrible. Comment faire? La réponse m'est venue de mes souvenirs de développement d'applications Android. Le framework Android impose que toutes actions lourdes ou risquées, comme un accès au système de fichiers ou au réseau, doit être exécutées en tâche de fond. En gros par un thread en parallèle. Ainsi, si l'action réalisée par le thread plante, elle ne fera pas planter le programme principal. Donc la solution à notre dysfonctionnement est de faire réaliser à un thread la récupération des données et l'envoi de la requête web.

Pour cela:
class myThread (threading.Thread): def __init__(self,name,s): threading.Thread.__init__(self) self.name=name self.sensortag=s def run(self): #Recuperation de la temperature infra rouge #tmpIR=sensortag.get_IRtmp() #print "%.2f" % tmpIR #Recuperation de la temperature et l humidite TabHUM=self.sensortag.get_HUM() #print "%.2f" % TabHUM[0] #print "%.2f" % TabHUM[1] #Recuperation de la temperature et de la pression TabPRES=self.sensortag.get_PRES() #print "%.2f" % TabPRES[0] #print "%.2f" % TabPRES[1] #Transmission des donnees sendval(TabPRES[0],TabHUM[1],TabPRES[1]) sys.exit() #*******************************************Fonction principale************************************ def main(): #Mise en daemon fpid = os.fork() if fpid!=0: # Fonctionne en daemon desormais. Le PID est fpid sys.exit(0) #Creation de l instance et connection sur le sensortag sensortag=Sensortag(ble_addr) # Create new thread #thread1 = myThread("sensortag",sensortag) while True: thread1 = myThread("sensortag",sensortag) thread1.start() thread1.join() time.sleep(30) if __name__ == "__main__": main()

Ce qui donne le script complet:
#***************************************************************************************************** # # Robert DORIGNY - www.doritique.fr le 20 aout 2014 # # Ce script est charge de recuperer les donnees des sondes du TI Sensortag CC2541 via une connexion # bluetooth low energy (BLE). N oubliez pas de modifier l'adresse BLE de votre Sensortag, et d'appuyer # sur le side button pour allumer le tag. # #***************************************************************************************************** import os import sys import pexpect import time import urllib2 import urllib import threading #Adresse BLE du sensortag (pour la connaitre tapez la commande hcitool lescan) ble_addr="BC:6A:29:AC:63:CD" tosigned = lambda n: float(n-0x10000) if n>0x7fff else float(n) tosignedbyte = lambda n: float(n-0x100) if n>0x7f else float(n) #Fonction chargee de la transmission des donnees def sendval(temp,hum,pres): data={} data['tp']='{:.2f}'.format(temp) data['hum']='{:.2f}'.format(hum) data['pr']='{:.2f}'.format(pres) data['sonde']='1' url_values=urllib.urlencode(data) #print(url_values) data=urllib2.urlopen("http://monsiteweb.fr/script.php"+"?"+url_values) #print("transmission OK") #Fonction de transformation de valeur hexa en float def floatfromhex(h): t = float.fromhex(h) if t > float.fromhex('7FFF'): t = -(float.fromhex('FFFF') - t) pass return t #Classe du sensortag class Sensortag: #Le constructeur def __init__(self,ble_addr): self.ble_addr=ble_addr self.child = pexpect.spawn('gatttool -b ' + ble_addr + ' --interactive') self.child.expect('[LE]>') print "Tentative de connection sur le sensortag..." self.child.sendline('connect') self.child.expect('[CON].*>') #Recup valeurs de calibration du barometre self.child.sendline('char-write-cmd 0x4f 02') #Active la lecture des datas de calibration self.child.expect('[LE]>') self.child.sendline('char-read-hnd 0x52') self.child.expect('descriptor: .*') rval=self.child.after.split() mycalib=[] for i in range(1,17) : mycalib.append(int(rval[i],16)) #print mycalib self.barometer = Barometer(mycalib) return #Getter de la temperature IR def get_IRtmp(self): #Active la sonde self.child.sendline('char-write-cmd 0x29 01') self.child.expect('[LE]>') self.child.sendline('char-read-hnd 0x25') self.child.expect('descriptor: .*') rval = self.child.after.split() objT = floatfromhex(rval[2] + rval[1]) ambT = floatfromhex(rval[4] + rval[3]) #Desactive la sonde #self.child.sendline('char-write-cmd 0x29 00') return(self.IRTmp(objT, ambT)) #Getter de l humidite et de la temperature def get_HUM(self): self.child.sendline('char-write-cmd 0x3C 01') self.child.expect('[LE]>') self.child.sendline('char-read-hnd 0x38') self.child.expect('descriptor: .*') rval=self.child.after.split() #print rval self.child.sendline('char-write-cmd 0x3C 00') return(self.HUMtmp(floatfromhex(rval[2]+rval[1])),self.HUMhum(floatfromhex(rval[4]+rval[3]))) def get_PRES(self): #Recup valeurs de pression et calcul self.child.sendline('char-write-cmd 0x4f 01') #Active la lecture des datas self.child.expect('[LE]>') self.child.sendline('char-write-cmd 0x4C 0x01 00') #Active la lecture des datas self.child.expect('[LE]>') self.child.sendline('char-read-hnd 0x4b') self.child.expect('descriptor: .*') rval=self.child.after.split() #print rval temp=int(rval[2] + rval[1],16) pres=int(rval[4] + rval[3],16) return self.barometer.calc(temp,pres) #Calcul de la temperature par le capteur IR def IRTmp(self,objT, ambT): m_tmpAmb = ambT/128.0 Vobj2 = objT * 0.00000015625 Tdie2 = m_tmpAmb + 273.15 S0 = 6.4E-14 # Calibration factor a1 = 1.75E-3 a2 = -1.678E-5 b0 = -2.94E-5 b1 = -5.7E-7 b2 = 4.63E-9 c2 = 13.4 Tref = 298.15 S = S0*(1+a1*(Tdie2 - Tref)+a2*pow((Tdie2 - Tref),2)) Vos = b0 + b1*(Tdie2 - Tref) + b2*pow((Tdie2 - Tref),2) fObj = (Vobj2 - Vos) + c2*pow((Vobj2 - Vos),2) temp = pow(pow(Tdie2,4) + (fObj/S),.25) temp = (temp - 273.15) #print "%.2f C" % temp #sendval(temp) return temp #Calcul de la temperature par le capteur d humidite def HUMtmp(self,temp): t = -46.85 + 175.72/65536.0 * temp #print "%.2f C" % t return t #Calcul de l humidite def HUMhum(self,hum): hum = float(int(hum) & ~0x0003); h = -6.0 + 125.0/65536.0 * hum #print "%.2f pourcents" % h return abs(h) #Classe particuliere pour le barometre class Barometer: def __init__(self, rawCalibration): self.m_barCalib = self.Calib( rawCalibration ) return def calc(self, rawT, rawP): self.m_raw_temp = tosigned(rawT) self.m_raw_pres = rawP bar_temp = self.calcBarTmp( self.m_raw_temp ) bar_pres = self.calcBarPress( self.m_raw_temp, self.m_raw_pres ) return( bar_temp, bar_pres) def calcBarTmp(self, raw_temp): c1 = self.m_barCalib.c1 c2 = self.m_barCalib.c2 val = long((c1 * raw_temp) * 100) temp = val >> 24 val = long(c2 * 100) temp += (val >> 10) return float(temp) / 100.0 def calcBarPress(self,Tr,Pr): c3 = self.m_barCalib.c3 c4 = self.m_barCalib.c4 c5 = self.m_barCalib.c5 c6 = self.m_barCalib.c6 c7 = self.m_barCalib.c7 c8 = self.m_barCalib.c8 # Sensitivity s = long(c3) val = long(c4 * Tr) s += (val >> 17) val = long(c5 * Tr * Tr) s += (val >> 34) # Offset o = long(c6) << 14 val = long(c7 * Tr) o += (val >> 3) val = long(c8 * Tr * Tr) o += (val >> 19) # Pression en Pa pres = ((s * Pr) + o) >> 14 return float(pres)/100.0 class Calib: def bld_int(self, lobyte, hibyte): return (lobyte & 0x0FF) + ((hibyte & 0x0FF) << 8) def __init__( self, pData ): self.c1 = self.bld_int(pData[0],pData[1]) self.c2 = self.bld_int(pData[2],pData[3]) self.c3 = self.bld_int(pData[4],pData[5]) self.c4 = self.bld_int(pData[6],pData[7]) self.c5 = tosigned(self.bld_int(pData[8],pData[9])) self.c6 = tosigned(self.bld_int(pData[10],pData[11])) self.c7 = tosigned(self.bld_int(pData[12],pData[13])) self.c8 = tosigned(self.bld_int(pData[14],pData[15])) class myThread (threading.Thread): def __init__(self,name,s): threading.Thread.__init__(self) self.name=name self.sensortag=s def run(self): #Recuperation de la temperature infra rouge #tmpIR=sensortag.get_IRtmp() #print "%.2f" % tmpIR #Recuperation de la temperature et l humidite TabHUM=self.sensortag.get_HUM() #print "%.2f" % TabHUM[0] #print "%.2f" % TabHUM[1] #Recuperation de la temperature et de la pression TabPRES=self.sensortag.get_PRES() #print "%.2f" % TabPRES[0] #print "%.2f" % TabPRES[1] #Transmission des donnees sendval(TabPRES[0],TabHUM[1],TabPRES[1]) sys.exit() #*******************************************Fonction principale************************************ def main(): #Mise en daemon fpid = os.fork() if fpid!=0: # Fonctionne en daemon desormais. Le PID est fpid sys.exit(0) #Creation de l instance et connection sur le sensortag sensortag=Sensortag(ble_addr) # Create new thread #thread1 = myThread("sensortag",sensortag) while True: thread1 = myThread("sensortag",sensortag) thread1.start() thread1.join() time.sleep(900) if __name__ == "__main__": main()

Conclusion

Nous avons désormais un script qui semble opérationnel. Dans le prochain article, nous verrons comment afficher nos données sur un beau graphique.










Pseudonyme (obligatoire) :
Adresse mail (obligatoire) :
Site web :




© 2017 www.doritique.fr par Robert DORIGNY