La série d’articles :
- Partie 1 : Installation capteur DS18B20 et lecture en ligne de commande
- Partie 2 : Lecture des valeurs avec un script Python basique
- Partie 3 : Lecture des valeurs avec un script Python avancé et stockage dans une base MySQL
- Partie 4 : Visualisation des données sur une page web
Le matériel nécessaire :
- 1 raspberry pi fonctionnel avec Raspbian installé
- 1 base de données MySQL ou MariaDB en local ou sur un autre serveur
Dans la partie 1 de cet article nous avons vu comment lire un capteur de température avec un raspberry.
L’intérêt de tout cela c’est surtout de pouvoir stocker les températures sur une longue durée et de pouvoir faire des jolis graphiques
Nous allons donc stocker tout ça dans une base MySQL. Je ne vais pas décrire ici l’installation et la configuration de MySQL , pour cela google est votre ami.
Pré-requis :
1 raspberry avec raspbian et python 2.7 (ne fonctionne pas avec python 3)
1 base de données déja fonctionnelle ( MySQL ou MariaDB, les 2 sont completement compatibles)
et bien sur avoir suivi la partie 1
le script qui va faire cela est en Python 2.7 , la base de données est une MySQL/MariaDB stockée sur un NAS Synology.
mais vous pouvez aussi installer MySQL sur le raspberry en local
Je parles de MariaDB car initialement j’avais développé le script pour MySQL mais suite au rachat de MySQL par Oracle , un fork MariaDB entièrement compatible libre a été crée. et sur Mon NAS Synology la migration a été automatique sans me demander mon avis. mais au final je n’ai eu aucune modif a faire sur le script .
Ne vous laissez pas impressionner par la taille du script , en réalité la partie essentielle fait 1 page , tout le reste c’est du control d’erreur
ces controles permettent les choses suivantes:
- éviter au script de planter si jamais la base est inaccessible
- stocker les données dans une base SQlite en local durant l’indisponibilité de la base MySQL
- restorer les mesures depuis SQlite vers MySQL dés que celle ci est de nouveau dispo.
Nous avons besoin d’ajouter 2 modules :
SQlite3 : installation SQlite3 qui va servir de backup
python-mysqldb : permet à python de dialoguer avec une base MySQL,MariaDB,SQLite
sudo apt-get install python-mysqldb sudo apt-get install sqlite3
Si vous ne voulez pas vous embeter avec la base SQlite de secours , je vais poster en bas de cet article un script beaucoup plus simple , ne comportant que l’essentiel
Vous pouvez retrouver ce script sur mon github au cas ou vous auriez des problèmes de copier/coller :
https://github.com/Jahislove/Thermo-pi/blob/master/thermo.py
Le script python est commenté pour vous aider a le comprendre
#!/usr/bin/python # -*- coding: utf-8 -*- #========================================================================= # thermo.py #------------------------------------------------------------------------- # by JahisLove - 2014, june # version 0.1 2014-06-16 #------------------------------------------------------------------------- # ce script lit les temperatures donnees par 3 sondes DS18B20 reliees # au raspberry pi et les stock dans une base MySQL # # # tested with python 2.7 on Raspberry pi (wheezy) and MariaDB 5.5.34 on NAS Synology DS411J (DSM 5) # #------------------------------------------------------------------------- # # la base de données doit avoir cette structure: #CREATE TABLE `PiTemp` ( # `id` int(11) NOT NULL AUTO_INCREMENT, # `date` datetime NOT NULL, # `sonde1` decimal(3,1) NOT NULL, # `sonde2` decimal(3,1) NOT NULL, # `sonde3` decimal(3,1) NOT NULL, # PRIMARY KEY (`id`) #) ENGINE=InnoDB DEFAULT CHARSET=latin1 ; #=================================================================== #----------------------------------------------------------# # package importation # #----------------------------------------------------------# import os import time import MySQLdb # MySQLdb must be installed by yourself import sqlite3 #-----------------------------------------------------------------# # constants : use your own values / utilisez vos propres valeurs # #-----------------------------------------------------------------# PATH_THERM = "/home/pi/thermo/" #path to this script DB_SERVER ='xxx.xxx.xxx.xxx' # MySQL : IP server (localhost if mySQL is on the same machine) DB_USER='xxxxxxxx' # MySQL : user DB_PWD='xxxxxxxx' # MySQL : password DB_BASE='xxxxxxxxx' # MySQL : database name # vous pouvez ajouter ou retirer des sondes en modifiant les 5 lignes ci dessous # ainsi que la derniere ligne de ce script : querydb(.... sonde1 = "/sys/bus/w1/devices/w1_bus_master1/28-000005f2424d/w1_slave" sonde2 = "/sys/bus/w1/devices/w1_bus_master1/28-000005f2764e/w1_slave" sonde3 = "/sys/bus/w1/devices/w1_bus_master1/28-000005f396a0/w1_slave" sondes = [sonde1, sonde2, sonde3] sonde_value = [0, 0, 0] #----------------------------------------------------------# # Variables # #----------------------------------------------------------# backup_row = 0 backup_mode = 0 if os.path.isfile(PATH_THERM + 'therm_bck.sqlite3'): # if sqlite exist then resume backup mode backup_mode = 1 #----------------------------------------------------------# # definition : database query with error handling # #----------------------------------------------------------# def query_db(sql): global backup_mode global backup_row try: db = MySQLdb.connect(DB_SERVER, DB_USER, DB_PWD, DB_BASE) cursor = db.cursor() #---------------------------------------------------------------# # Normal MySQL database INSERT # # Fonctionnement normal, insertion dans MySQL # #---------------------------------------------------------------# if backup_mode == 0: cursor.execute(sql) db.commit() db.close() #---------------------------------------------------------------# # RESTORE : when MySQL is available again : restore from SQlite # # restauration depuis SQlite vers MySQL apres une indispo de MySQL# #---------------------------------------------------------------# else: logfile = open(PATH_THERM + "thermo.log", "a") log = time.strftime('%Y-%m-%d %H:%M:%S') + " INFO : MySQL is OK now : Restore mode started\n" logfile.write(log) db_bck = sqlite3.connect(PATH_THERM + 'therm_bck.sqlite3') db_bck.text_factory = str #tell sqlite to work with str instead of unicode cursor_bck = db_bck.cursor() cursor_bck.execute("""SELECT 'DEFAULT' as id, date, sonde1, sonde2, sonde3 FROM PiTemp ORDER BY date ASC """) result_pitemp = cursor_bck.fetchall () for row in result_pitemp: cursor.execute("""INSERT INTO PiTemp VALUES {0}""".format(row)) db_bck.close() log = time.strftime('%Y-%m-%d %H:%M:%S') + " INFO : " + str(backup_row) + " rows restored to MySQL\n" logfile.write(log) backup_row = 0 backup_mode = 0 os.remove(PATH_THERM + 'therm_bck.sqlite3') log = time.strftime('%Y-%m-%d %H:%M:%S') + " INFO : restore done, sqlite3 file deleted, returning to normal mode\n" logfile.write(log) cursor.execute(sql) db.commit() db.close() logfile.close #---------------------------------------------------------------# # BACKUP : when MySQL is down => local SQlite INSERT # # si MySQL est KO , on créé une base SQlite temporaire # #---------------------------------------------------------------# except MySQLdb.Error: db_bck = sqlite3.connect(PATH_THERM + 'therm_bck.sqlite3') cursor_bck = db_bck.cursor() if backup_mode == 0: #create table on first run logfile = open(PATH_THERM + "thermo.log", "a") log = time.strftime('%Y-%m-%d %H:%M:%S') + " WARN : MySQL is down : Backup mode started\n" logfile.write(log) create_pitemp = """CREATE TABLE IF NOT EXISTS PiTemp (`date` datetime NOT NULL, sonde1 decimal(3,1) NOT NULL, sonde2 decimal(3,1) NOT NULL,sonde3 decimal(3,1) NOT NULL ) ;""" cursor_bck.execute(create_pitemp) log = time.strftime('%Y-%m-%d %H:%M:%S') + " WARN : Sqlite created\n" logfile.write(log) logfile.close backup_mode = 1 cursor_bck.execute(sql) backup_row += 1 db_bck.commit() db_bck.close() #----------------------------------------------------------# def read_file(sonde): """ fonction de lecture d'une sonde """ try: f = open(sonde, 'r') lines = f.readlines() f.close() except: time.sleep(60) try: f = open(sonde, 'r') lines = f.readlines() f.close() except: logfile = open(PATH_THERM + "thermo.log", "a") log = time.strftime('%Y-%m-%d %H:%M:%S') + " WARN : Sonde not found\n" logfile.write(log) logfile.close exit finally: return lines #----------------------------------------------------------# # code principal # #----------------------------------------------------------# # initialize Raspberry GPIO and DS18B20 os.system('sudo /sbin/modprobe w1-gpio') os.system('sudo /sbin/modprobe w1-therm') time.sleep(2) datebuff = time.strftime('%Y-%m-%d %H:%M:%S') #formating date for mySQL for (i, sonde) in enumerate(sondes): lines = read_file(sonde) while lines[0].strip()[-3:] != 'YES': # read 3 last char from line 0 and retry if not yes time.sleep(0.2) lines = read_file(sonde) temp_raw = lines[1].split("=")[1] # when YES then read temp (after =) in second line sonde_value[i] = round(int(temp_raw) / 1000.0, 1) #ecriture dans la base query_db("""INSERT INTO PiTemp (date, sonde1, sonde2, sonde3) VALUES ('%s','%s','%s','%s') """ % (datebuff, sonde_value[0], sonde_value[1], sonde_value[2]))
Voila , il ne vous reste plus qu’a lancer ce script a intervalle régulier avec la crontab
Ci dessous , je vous met le meme script simplifié à l’extreme , il se contente de l’essentiel , il est plus facile a comprendre mais il n’y a aucun controle d’erreur
#!/usr/bin/python # -*- coding: utf-8 -*- #================================================================ # thermo.py #---------------------------------------------------------------- # by JahisLove - 2014, june # version 0.1 2014-06-16 # # la base de données doit avoir cette structure: #CREATE TABLE `PiTemp` ( # `id` int(11) NOT NULL AUTO_INCREMENT, # `date` datetime NOT NULL, # `sonde1` decimal(3,1) NOT NULL, # `sonde2` decimal(3,1) NOT NULL, # `sonde3` decimal(3,1) NOT NULL, # PRIMARY KEY (`id`) #) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=28 ; #================================================================ #----------------------------------------------------------# # package importation # #----------------------------------------------------------# import os import time import MySQLdb # MySQLdb must be installed by yourself #-----------------------------------------------------------------# # constants : use your own values / utilisez vos propres valeurs # #-----------------------------------------------------------------# PATH_THERM = "/home/pi/thermo/" #path to this script DB_SERVER ='xxx.xxx.xxx.xxx' # MySQL : IP server (localhost if mySQL is on the same machine) DB_USER='xxxxxxxx' # MySQL : user DB_PWD='xxxxxxxx' # MySQL : password DB_BASE='xxxxxxxxx' # MySQL : database name # vous pouvez ajouter ou retirer des sondes en modifiant les 5 lignes ci dessous # ainsi que la derniere ligne de ce script : querydb(.... sonde1 = "/sys/bus/w1/devices/w1_bus_master1/28-000005f2424d/w1_slave" sonde2 = "/sys/bus/w1/devices/w1_bus_master1/28-000005f2764e/w1_slave" sonde3 = "/sys/bus/w1/devices/w1_bus_master1/28-000005f396a0/w1_slave" sondes = [sonde1, sonde2, sonde3] sonde_value = [0, 0, 0] #----------------------------------------------------------# # definition : database query # #----------------------------------------------------------# def query_db(sql): try: db = MySQLdb.connect(DB_SERVER, DB_USER, DB_PWD, DB_BASE) #creation du connecteur de la base cursor = db.cursor() # creation du curseur if backup_mode == 0: cursor.execute(sql) #execution de la requete db.commit() db.close() #----------------------------------------------------------# # lit le fichier sonde , def read_file(sonde): try: f = open(sonde, 'r') lines = f.readlines() f.close() except: exit #----------------------------------------------------------# # code # #----------------------------------------------------------# # initialize Raspberry GPIO and DS18B20 # si vous avez installé ces modules au boot dans /etc/modules # vous pouvez supprimer les 3 lignes ci dessous os.system('sudo /sbin/modprobe w1-gpio') os.system('sudo /sbin/modprobe w1-therm') time.sleep(2) datebuff = time.strftime('%Y-%m-%d %H:%M:%S') #formating date for mySQL for (i, sonde) in enumerate(sondes): lines = read_file(sonde) while lines[0].strip()[-3:] != 'YES': # read 3 last char from line 0 and retry if not yes time.sleep(0.2) lines = read_file(sonde) temp_raw = lines[1].split("=")[1] # when YES then read temp (after =) in second line sonde_value[i] = round(int(temp_raw) / 1000.0, 1) query_db("""INSERT INTO PiTemp (date, sonde1, sonde2, sonde3) VALUES ('%s','%s','%s','%s') """ % (datebuff, sonde_value[0], sonde_value[1], sonde_value[2])) # on INSERT dans la base
Super, c’est exactement ce que je cherchais !
Un grand merci. On attends la partie 4 avec impatience…
J’aimeJ’aime
Bonjour le script me renvoi une erreur d’indentation en ligne 149 ???
J’aimeJ’aime
fixed
J’aimeJ’aime
je vois que tu as trouvé tout seul 🙂
J’aimeJ’aime
Bonjour,
Peux tu m’expliquer les paramètres (je comprends pas tout !!!) dans cette fonction car je trouve qu’il y a beaucoup de guillemets et des %s ???
query_db(« » »INSERT INTO PiTemp (date, sonde1, sonde2, sonde3) VALUES (‘%s’,’%s’,’%s’,’%s’)
« » » % (datebuff, sonde_value[0], sonde_value[1], sonde_value[2]))
Merci de ton aide.
M. Sabarthes
J’aimeJ’aime
alors les 3 guillemets en python sont surtout utilisé pour les requetes SQL . en fait ca permet de pouvoir écrire une commande sur plusieurs lignes et en plus a l’intérieur tu peux aussi utiliser un guillemet simple pour certaines instructions
les %s sont utilisés pour remplacer les variables dans les requetes SQL en python . en fait dans les requetes SQL les variables python ne sont pas interprété. pour contourner ca on utilise les %s et apres la requete SQL on ajoute un % suivi des vraies variables . chaque %s sera remplacé par la valeur de la variable dans l’ordre ou elles sont indiquées
J’aimeJ’aime
Bonjour,
Je te remercie pour ces infos très précises, car c’est pas très bien expliqué dans les docs. J’avais du mal à passer les paramètres dans la requête.
A bientôt. Marc
J’aimeJ’aime
meme erreur mais pas trouve la correction
peux tu me ce quil faut faire
J’aimeJ’aime
si tu as une erreur d’indentation c’est que tu as un problème de copier/coller .
l’indentation en python est super important, un espace en trop et c’est une erreur.
l’indentation c’est les espaces en début de ligne
exemple sur cette image, on voit bien l’alignement des commandes , la norme c’est 4 espaces a chaque fois
par exemple pour la commande if , les 3 lignes suivantes font partie du IF car elle sont indenté par 4 espaces
J’aimeJ’aime
l erreur provient du code en lui meme
apres try il faut except et la il ny a pas
la partie 4 sort qd j en ai besoin ..
J’aimeJ’aime
Salut, comment lancer le script en « crontab »? Est-ce qu’il n’est pas mieux de faire un service qui fait un loop toutes les 5 minutes?
J’aimeJ’aime
les 2 sont possibles , mais un service est prévu pour tourner en permanence alors qu’une crontab est spécialement prévue pour ce genre de lancement.
la crontab c’est très simple en fait , fait une recherche google pour la syntaxe exacte .
ça s’edite avec crontab -e
voici la mienne :
0,15,30,45 * * * * python /home/pi/thermo/thermo.py
les 5 premiers champs corresponde à la date suivi de la commande a lancer, ici :python /home/pi/thermo/thermo.py
dans ce cas c’est toutes les 0 , 15 , 30, 45 minutes de chaque heure , de chaque jour…
si tu veux toutes les heures pile c’est 0 * * * *
si tu veux 10h30 chaque jour c’est 30 10 * * *
J’aimeJ’aime
excellent travail !!
je veut bien savoir comment faire la Visualisation des données sur une page web (partie 4) que j’ai du mal a la trouver 😥
J’aimeJ’aime
Mea culpa , c’est vrai que je n’avais jamais publié la partie 4 , c’est chose faite maintenant , tu pourras y trouver un exemple de graphique
J’aimeJ’aime
J’ai moi aussi ce fameux problème d’indentation en ligne 150 avec le 1ier script ou ligne 60 du second (le simplifié).
J’ai beau regarder et compter tous les espaces pour voir si ce n’est pas un pbl de copier/coller, je n’arrive pas a faire tourner ce script, j’ai toujours cette erreur, pouvez-vous me guider ?
Cdlt
J’aimeJ’aime
Salut , en Python l’indentation est hyper importante . donc le problème vient forcement du copier coller.
vérifie que l’indentation représente bien 4 espaces et non pas une tabulation.
si vraiment tu ne trouve pas , tu peux télécharger mon script sur github :
https://github.com/Jahislove/Thermo-pi/blob/master/thermo.py
J’en profite pour ajouter ce lien dans l’article
J’aimeJ’aime
Bravo, c’est super. J’avais le problème d’indentation, mais c’est résolu. Pas compliqué.
Cependant, j’ai une erreur avec datebuff. C’est vrai sur le net, c’est dit que c’est une commande sqlite. pour ne pas insérer la commande mysql ?
J’aimeJ’aime
heu j’ai pas vraiment compris ta question ,normalement le script écrit dans une base MySQL. mais si jamais la base est KO alors il crée une base SQlite temporaire puis dès que MySQL redevient OK alors il recopie tout dedans avant d’effacer la SQlite.
il faut donc également avoir installé SQlite sur ta machine , si tu ne veux pas te servir de cette fonctionnalité alors prends plutot le 2 eme script
J’aimeJ’aime
Une autre petite question concernant l’emplacement de la base de donnée.
Dans phpmyadmin j’ai la base « PiTemp » qui est dans la structure nommée « domotique », je dois donc bien rentrer ==> DB_BASE= ‘domotique’ ?
J’ai toujours ce problème d’intentation avec le deuxième script, cella peut-il venir d’un problème de droits (user SQL), ou bien de la version de SQL, je ne pense pas mais je préfère demander quand même car je ne vois pas ou peut être le soucis, j’ai tous vérifié 10 fois.
Merci pour votre aide.
J’aimeJ’aime
oui c’est bien ca DB_BASE=’domotique’ , pour utiliser les termes exacts : domotique est le nom de la base , et PiTemp est le nom de la table. une base peut contenir plusieurs table.
non un problème d’indentation c’est uniquement un probleme d’alignement des lignes du scripts
J’aimeJ’aime
en fait j’ai cette erreur :
Traceback (most recent call last):
File « sonde_temp.py », line 190, in
« » » % (datebuff, sonde_value[0]))
File « sonde_temp.py », line 95, in query_db
cursor_bck.execute(« » »SELECT ‘DEFAULT’ as id, datebuff, sonde1 FROM PiTemp ORDER BY date ASC « » »)
sqlite3.OperationalError: no such column: datebuff
tu peux me dire si tu comprends quelque chose ?
je crois que ma base sqlite n’est pas créée, mais ca veut dire qu’il route en erreur !
Merci.
J’aimeJ’aime
il ne trouve pas la colonne datebuff dans ta table . ce qui me semble normal vu que tu semble avoir modifié la requete . lors de la creation mon script crée une colonne date :
create_pitemp = « » »CREATE TABLE IF NOT EXISTS PiTemp (`date` datetime NOT NULL, sonde1 decimal(3,1) NOT NULL, sonde2 decimal(3,1) NOT NULL,sonde3 decimal(3,1) NOT NULL) ; » » »
et toi tu essaye de lire une colonne datebuff , ca peut pas marcher
J’aimeJ’aime
Merci de ta disponibilité.
Effectivement, j’ai changé le nom de la variable date par datebuff car, je pensais que le problème venait de là, mais le résultat est le même.
voir mysql :
mysql> DESCRIBE PiTemp;
+———-+————–+——+—–+———+—————-+
| Field | Type | Null | Key | Default | Extra |
+———-+————–+——+—–+———+—————-+
| id | int(11) | NO | PRI | NULL | auto_increment |
| sonde1 | decimal(3,2) | NO | | NULL | |
| datebuff | datetime | NO | | NULL | |
+———-+————–+——+—–+———+—————-+
3 rows in set (0.00 sec)
par contre comme, je n’ai qu’une sonde, j’ai enlevé les autres dans ton code…
apparemment, ton script ne trouve pas l’accès à mysql :
fichier thermo log :
2016-02-18 22:54:39 WARN : MySQL is down : Backup mode started
2016-02-18 22:54:39 WARN : Sqlite created
2016-02-18 23:03:23 INFO : MySQL is OK now : Restore mode started
2016-02-18 23:03:23 INFO : 0 rows restored to MySQL
2016-02-18 23:03:23 INFO : restore done, sqlite3 file deleted, returning to normal mode
2016-02-18 23:03:23 WARN : MySQL is down : Backup mode started
2016-02-18 23:03:23 WARN : Sqlite created
2016-02-19 13:23:08 INFO : MySQL is OK now : Restore mode started
2016-02-19 13:23:08 INFO : 0 rows restored to MySQL
2016-02-19 13:23:08 INFO : restore done, sqlite3 file deleted, returning to normal mode
2016-02-19 13:23:08 WARN : MySQL is down : Backup mode started
2016-02-19 13:23:09 WARN : Sqlite created
2016-02-19 13:27:18 INFO : MySQL is OK now : Restore mode started
2016-02-19 13:27:18 INFO : 0 rows restored to MySQL
2016-02-19 13:27:18 INFO : restore done, sqlite3 file deleted, returning to normal mode
2016-02-19 13:27:18 WARN : MySQL is down : Backup mode started
2016-02-19 13:27:18 WARN : Sqlite created
2016-02-19 13:29:23 INFO : MySQL is OK now : Restore mode started
2016-02-19 13:41:30 INFO : MySQL is OK now : Restore mode started
2016-02-19 13:44:13 INFO : MySQL is OK now : Restore mode started
2016-02-19 13:46:38 INFO : MySQL is OK now : Restore mode started
2016-02-19 14:51:19 INFO : MySQL is OK now : Restore mode started
2016-02-19 14:55:33 INFO : MySQL is OK now : Restore mode started
2016-02-19 14:55:33 INFO : 0 rows restored to MySQL
2016-02-19 14:55:33 INFO : restore done, sqlite3 file deleted, returning to normal mode
2016-02-19 14:55:33 WARN : MySQL is down : Backup mode started
2016-02-19 14:55:33 WARN : Sqlite created
2016-02-19 17:53:48 INFO : MySQL is OK now : Restore mode started
2016-02-19 19:16:44 INFO : MySQL is OK now : Restore mode started
2016-02-19 19:18:33 INFO : MySQL is OK now : Restore mode started
2016-02-19 21:04:03 INFO : MySQL is OK now : Restore mode started
J’aimeJ’aime
effectivement le script n’arrive pas à accèder à mysql.
vérifie les droits de ton utilisateur pour ta base mysql ( dans phpmyadmin , onglet utilisateurs)
. il y a une double sécurité dans mysql:
– les droits de lecture/ecriture pour l’utilisateur sur la base
– le droit d’accéder depuis un autre client si jamais ton script ne tourne pas sur la meme machine
J’aimeJ’aime
ok mon script tourne sur la même machine. Je le lance en root.
je n’ai pas vérifier php encore. je ragarde… merci encore…
J’aimeJ’aime
salut Jah,
j’ai un serieux problème que je n’arrive pas à résoudre : apache ne focntionne pas correctement :
en console :
root@raspberrypi:/home/pi# /etc/init.d/apache2 restart
[….] Restarting apache2 (via systemctl): apache2.serviceJob for apache2.service failed. See ‘systemctl status apache2.service’ and ‘journalctl -xn’ for details.
failed!
dans le journalctl:
févr. 20 13:34:35 raspberrypi systemd[1]: Failed to start LSB: Apache2 web server.
févr. 20 13:34:35 raspberrypi systemd[1]: Unit apache2.service entered failed state.
févr. 20 13:39:01 raspberrypi CRON[2759]: pam_unix(cron:session): session opened for user root by (uid=0)
févr. 20 13:39:01 raspberrypi CRON[2766]: (root) CMD ( [ -x /usr/lib/php5/sessionclean ] && /usr/lib/php5/sessionclean)
févr. 20 13:39:02 raspberrypi CRON[2759]: pam_unix(cron:session): session closed for user root
févr. 20 14:09:01 raspberrypi CRON[3065]: pam_unix(cron:session): session opened for user root by (uid=0)
févr. 20 14:09:01 raspberrypi CRON[3072]: (root) CMD ( [ -x /usr/lib/php5/sessionclean ] && /usr/lib/php5/sessionclean)
févr. 20 14:09:01 raspberrypi CRON[3065]: pam_unix(cron:session): session closed for user root
févr. 20 14:09:15 raspberrypi sudo[3099]: root : TTY=pts/0 ; PWD=/home/pi ; USER=root ; COMMAND=/bin/journalctl
févr. 20 14:09:15 raspberrypi sudo[3099]: pam_unix(sudo:session): session opened for user root by (uid=0)
je ne comprends car je desinstalle et reinstalle, toujours la même chose.
saurais-tu m’aiguiller dans ma résolution de problème ?
merci d’avance…
J’aimeJ’aime
et journalctl -xn
root@raspberrypi:/home/pi# sudo journalctl -xn
— Logs begin at sam. 2016-02-20 12:07:48 UTC, end at sam. 2016-02-20 14:19:04 UTC. —
févr. 20 14:09:01 raspberrypi CRON[3072]: (root) CMD ( [ -x /usr/lib/php5/sessionclean ] && /usr/lib/php5/sessionclean)
févr. 20 14:09:01 raspberrypi CRON[3065]: pam_unix(cron:session): session closed for user root
févr. 20 14:09:15 raspberrypi sudo[3099]: root : TTY=pts/0 ; PWD=/home/pi ; USER=root ; COMMAND=/bin/journalctl
févr. 20 14:09:15 raspberrypi sudo[3099]: pam_unix(sudo:session): session opened for user root by (uid=0)
févr. 20 14:09:15 raspberrypi sudo[3099]: pam_unix(sudo:session): session closed for user root
févr. 20 14:17:01 raspberrypi CRON[3213]: pam_unix(cron:session): session opened for user root by (uid=0)
févr. 20 14:17:01 raspberrypi CRON[3220]: (root) CMD ( cd / && run-parts –report /etc/cron.hourly)
févr. 20 14:17:01 raspberrypi CRON[3213]: pam_unix(cron:session): session closed for user root
févr. 20 14:19:04 raspberrypi sudo[3277]: root : TTY=pts/0 ; PWD=/home/pi ; USER=root ; COMMAND=/bin/journalctl -xn
févr. 20 14:19:04 raspberrypi sudo[3277]: pam_unix(sudo:session): session opened for user root by (uid=0)
J’aimeJ’aime
Désolé la dessus j’y connait pas grand chose.
J’aimeJ’aime
bonjour
j’ai des soucis
pour ce script il faut bien faire sudo nan therm.py ?
DB_SERVER =’xxx.xxx.xxx.xxx’ # MySQL : IP server (localhost if mySQL is on the same machine) — c’est bien ip du raspberry?
DB_BASE=’xxxxxxxxx’ # MySQL : database name ——- la je sais pas trop c’est therm?
merci
J’aimeJ’aime
il faut faire sudo python therm.py
l’adresse IP c’est celle de la machine ou se trouve la base MySQL , c’est pas forcement le raspberry , ca depends sur quelle machine tu as installé MySQL
le database name c’est le nom que tu as donné a ta base lorsque tu l’as créé
J’aimeJ’aime
j’utilise que le raspberry moi j’ai mis l’adresse ip du raspberry celle que j’utilise pour putty
la database c’est sous python?
desolé je decouvre seulement le raspberry
merci
J’aimeJ’aime
j’ai le message suivant
file « thermo.py », line 193
status API training shop blog about
J’aimeJ’aime
A mon avis tu as brulé quelques étapes 🙂 mon script est prévu pour stocker les données dans une base MySQL , mais il faut deja en avoir une installée quelquepart. je te conseille de demander a ton ami google pour plus d’info , je ne peux pas t’aider la dessus la mienne est installé sur un NAS synology
J’aimeJ’aime
ok merci pour ton aide je vais essayé de trouver mais pas evident lorsqu’on debute
bonne soirée
J’aimeJ’aime
bonjour je viens de créer une base de donnéeen utilisant ce tuto:
http://fr.wikihow.com/créer-une-base-de-données-MySQL
c’est bien ca?
merci
J’aimeJ’aime
Bonjour Jah,
J’ai un petit soucis lorsque je lance le pyhton:
File « Temperature.py », line 181, in
lines = read_file(sonde)
File « Temperature.py », line 167, in read_file
return lines
Que faire ?
Merci de me répondre au plus vite.
J’aimeJ’aime
la comme ca franchement j’en sais rien , les lignes en questions sont correctes , mais le problème doit venir en amont , ta sonde est elle bien reconnu par le raspberry , ta base MySQL fonctionne -t-elle correctement ?
J’aimeJ’aime
Bonjour, premièrement merci pour le partage.
Je bosse sur un projet similaire mais je dois stocker les données de 1200 capteurs sur une base de données MySQL je souhaite savoir comment t’as structuré ta base?
J’aimeJ’aime
Bonjour ,
La structure est assez simple une table avec ces champs :
id / datetime / sonde1 / sonde2 / sonde3 …
id est un numero en auto increment (utile pour les requete de lecture par la suite)
datetime est au format mysql 2016-01-01 00:00:00
pour les formats des champs sonde , je te conseille fortement de ne pas utiliser de type de données qui utilise beaucoup d’octets (FLOAT ou DOUBLE par exemple), sinon vu le nombre de champ ta base va vite grossir pour rien .
utilise plutot DECIMAL(4,2) (4 chiffres en tout , dont 2 apres la virgule)
par contre 1200 sondes, c’est enorme 🙂
je ne sais pas si ca ne va pas ralentir mysql. tu peux peux etre faire plusieurs tables plus petites
Edit : d’ailleurs la réponse était dans le code au dessus :
# la base de données doit avoir cette structure:
#CREATE TABLE `PiTemp` (
# `id` int(11) NOT NULL AUTO_INCREMENT,
# `date` datetime NOT NULL,
# `sonde1` decimal(3,1) NOT NULL,
# `sonde2` decimal(3,1) NOT NULL,
# `sonde3` decimal(3,1) NOT NULL,
# PRIMARY KEY (`id`)
#) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=28 ;
J’aimeAimé par 1 personne
Salut BigData, dans le cadre de 1200 Capteurs il faut voir plutôt une base de donnée plus structurée.
Ex: Un table Capteurs(Capteur_Id, Nom, Description) et un table Valeurs(Capteur_Id, Date, Valeur).
J’aimeJ’aime
Bonjour,
J’ai respecté ce qui est dit dans ce tutoriel super bien fait !! en particulier :
sudo apt-get install python-mysqldb
sudo apt-get install sqlite3
quand le fais import MySQLdb dans le scrip, j’ai comme réponse : ImportError No module named ‘MySQLdb’ ….
si vous pouvez m’éclairer.
Merci.
Marc.
J’aimeJ’aime
c’est étrange on dirait que MySQLdb n’est pas installé, essaye de faire un « sudo apt-update » avant pour bien mettre a jour le référentiels des packages puis refait le sudo apt-get install python-mysqldb
J’aimeJ’aime
Merci. je suis d’accord : ça me parait bizarre, ma base de donnée est bien présente car j’y accède bien avec phpmyadmin !!! je vais essayer demain se faire un update et un install python-mysqldb dans la matinée et je t’en dirait plus. Marc.
J’aimeJ’aime
Bonjour,
En fait ça fonctionne très bien avec Python 2.7.9 et ça ne fonctionne pas pavec Python 3.4.2
Marc.
J’aimeAimé par 1 personne
ha oui forcement , effectivement , je développe sous 2.7, tout s’explique
J’aimeJ’aime
Bonjour.
Je suis habitué à python3 et MySQLdb n’existe pas pour python3.
J’ai tenté la commande proposée « sudo apt-get install python-mysqldb », mais je ne peux l’importer qu’avec python2. Or j’ai modifié les parties de codes pour mon usage avec python3 et ne sais les modifier en python2 pour faire cette partie du tutoriel.
Et je ne trouve que beaucoup de confusion avec google.
Y aurait-il une solution simple avec un « pip install » ou un « apt-get install python3-mysqldb.
J’aimeJ’aime
Bonjour ,
effectivement mysqldb n’existe toujours pas sur python 3 , mais il existe plusieurs alternatives
voir la reponse ici : http://stackoverflow.com/questions/4960048/python-3-and-mysql
je pense que la 4eme option (mysqlclient) semble la plus prometteuse
voir ici pour l’installation https://github.com/PyMySQL/mysqlclient-python
l’option PyMySQL semble bien aussi http://stackoverflow.com/questions/23376103/python-3-4-0-with-mysql-database
bonne chance , n’hésite pas a poster ici la solution que tu as réussi a faire fonctionner
J’aimeJ’aime
Encore une question.
Moi, je souhaite faire un datalogger, donc récupérer mes données (températures, pressions, tensions) en fonction du temps.
Si je comprends bien votre approche, vous avez ce petit bout de code que vous lancer régulièrement avec un truc qui s’appelle crontab. Le bout de code s’occupe de l’acquisition des températures et de les « lier » à un « TimeStamp » qui se fait à la ligne 179 dans :
« datebuff = time.strftime(‘%Y-%m-%d %H:%M:%S’) #formating date for mySQL »
valeur qui est transmise à MySQL en même temps que les températures.
Hors, vous indiquez que le capteur DS18B20 à besoin d’un temps de conversion de 750ms en 12bits, ce qui est notre cas.
En ajoutant le 200ms du « time.sleep(0.2) » de la ligne 184, cela fait 950ms nécessaire pour chaque mesure.
Dans les faits, la 3ème mesure est faite environ à TimeStamp+2.7s.
Pour une mesure tous les 1/4 d’heure ou toute les heures, c’est peut être acceptable, mais avec des valeurs pouvant varier rapidement, (tension d’un capteur quelconque), quelle serait la pratique à adopter ?
Affecter un TimeStamp à chaque valeur au moment le plus près de sa mesure ?
D’autre part, pour mon usage, où je lance une procédure de test de quelques heures en local, le « truc » fait son cycle, récupère les données correctement horodatées, je pense que l’utilisation d’une boucle « while(1): » est plus adaptée. J’enregistre les données en local ou dans un buffer, et quand mon test est terminé ou mon buffer plein, je transfert les data dans un lieu sûr.
Qu’en pensez vous ?
J’aimeJ’aime
Bonjour ,
effectivement j’utilise un seul timestamp puis une boucle sur 3 sondes , forcement le temps ne correspond pas a la réalité. mais cela permet d’inserer 1 seule ligne dans une table avec 1 timestamp + 3 valeurs.
tu peux mettre le timestamp dans la boucle au plus pres de chaque mesure de sonde , mais cela implique de revoir l’ecriture en base. tu te retrouvera avec 3 lignes a inserer et le mieux est des les mettre dans 3 tables separées
pour ta 2eme question , pour ce cas , il ne faut pas utiliser la crontab qui n’est pas prévu pour une utilisation intensive.
il faut mieux utiliser une boucle while infinie effectivement. ensuite plusieurs options mais il faudra faire des tests pour voir comment réagit ta base.
soit tu écris en base a chaque mesure
soit tu bufferize un certain nombre de mesure avant d’écrire en base
regarde un autre de mes script ici qui utilise exactement cette methode https://github.com/Jahislove/hargassner-python/blob/master/harg.py
ça se passe a la fin dans la boucle while true
par la suite si tu veux grimper d’un cran dans python , je te conseille de te pencher sur les thread ( mon script les utilise aussi)
un thread est une portion de script qui tourne en parallele du script principal. cela permet de faire plusieurs choses en meme temps .
par exemple tu pourrai avoir un thread qui mesure une sonde toutes les 5 sec et un autre qui mesure une autre sonde toutes les seccondes …
J’aimeJ’aime
Merci pour ces réponses très utiles.
J’avais déjà vu cette histoire de Thread en python et j’en avais perçu « l’utilité » sans pouvoir les mettre en œuvre par manque d’expérience.
Du reste, pour comprendre ton code, pour moi qui est débutant, la marche est trop haute pour comprendre tout ce qui se passe !
Pourtant, ça à l’air d’être exactement ce que je voudrais mettre en œuvre.
Pourrait-on espérer un tuto détaillé à la manière de ceux de ce blog ?
Le soucis est qu’il faut tout ingurgiter d’un cout ! python, SQL et…. PHP.
J’aimeJ’aime
salut tres bon tuto mais pour ceux comme moi qui ne maitrise pas du tout python et page web vaut mieux passé par un logiciel domotique comme jeedom
A+
J’aimeJ’aime
Bonjour.
J’essaie la partie 3 mais j’ai toujours l’erreur suivante :
« Traceback (most recent call last):
File « thermo.py », line 192, in
« » » % (datebuff, sonde_value[0], sonde_value[1], sonde_value[2]))
File « thermo.py », line 141, in query_db
cursor_bck.execute(sql)
sqlite3.OperationalError: no such table: PiTemp »
Je ne vois pas comment débloquer cette situation.
Ce que je ne comprends pas, c’est qu’il me semble comprendre que la table « PiTemp » doit être au cas ou elle n’existe pas.
(Je n’ai pas de serveur MySQL installé pour le moment.)
J’aimeJ’aime
en fait le script essaye d’abord d’écrire dans la base MySQL , si celle ci n’est pas joignable alors il crée un fichier SQlite en local , à l’intérieur il crée lui même la table PiTemp puis écrit dedans en attendant .
mais est ce que tu as au moins installé SQlite3 sur ta machine?
J’aimeJ’aime
Oui SQLite3 est maintenant installé, sinon, j’aurai « No module named sqlite3 » comme j’avais en effet avant de l’installer !
Je vérifie tout de même :
# sudo apt-get install sqlite3
Reading package lists… Done
Building dependency tree
Reading state information… Done
sqlite3 is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 17 not upgraded.
Mais ça ne marche toujours pas.
J’aimeJ’aime
J’ai l’impression qu’il n’arrive pas a créer la table pitemp , il est possible qu’une version plus récente de SQlite nécessite un ajustement des commandes .
essaye de faire un test a la main :
creation d’une base test: tu tapes sqlite3 test en ligne de commande .
creation de la table :
CREATE TABLE IF NOT EXISTS PiTemp (`date` datetime NOT NULL,sonde1 decimal(3,1) NOT NULL, sonde2 decimal(3,1) NOT NULL,sonde3 decimal(3,1) NOT NULL) ; n’oublie pas le point virgule a la fin
liste les tables : .tables
J’aimeJ’aime
.tables renvoie bien
PiTemp
De plus, depuis tout à l’heure, j’ai installé MySQL-server en local sur la PI, dans le code, j’ai mis:
PATH_THERM = « /home/pi/thermo/ » #path to this script
DB_SERVER = ‘localhost’ # MySQL : IP server (localhost if mySQL is on the same machine)
DB_USER=’owl_intuition’ # MySQL : user
DB_PWD=’2006′ # MySQL : password
DB_BASE=’owl_intuition’ # MySQL : database name
Mais j’ai toujours exactement la même erreur ! Il semble que ça n’essaie même pas d’enregistrer dans la base mysql locale.
J’aimeJ’aime
la librairie mysqldb est bien installée également?
dans mysql as tu bien créé la table Pitemp a la main ( le script ne le fait pas ) la requete pour creer la table est dans le commentaire au debut du script
J’aimeJ’aime
Oui, la librairie mysqldb est bien installée.
Par contre je n’avais pas créé la table PiTemp.
Après pas mal de difficulté, je pense l’avoir crée mais toujours le même blocage malgré tout :
Traceback (most recent call last):
File « thermo2.py », line 192, in
« » » % (datebuff, sonde_value[0], sonde_value[1], sonde_value[2]))
File « thermo2.py », line 96, in query_db
cursor_bck.execute(« » »SELECT date, sonde1, sonde2, sonde3 FROM PiTemp ORDER BY date ASC « » »)
sqlite3.OperationalError: no such table: PiTemp
J’aimeJ’aime
verifie qu’il ne reste pas un fichier therm_bck.sqlite3 dans le repertoire avant de lancer le script , si oui supprime le.
on va tester en desactivant la partie sqlite , transforme en commentaire la partie apres :
#—————————————————————#
# BACKUP : when MySQL is down => local SQlite INSERT #
#—————————————————————#
except MySQLdb.Error:
….
jusque (inclu)
db_bck.close()
puis ajoute apres le
except MySQLdb.Error:
____print « mysql KO »
(4 espaces au lieu des tiret bas)
cette fois si il n’arrive pas a ecrire dans mysql , il affichera KO au lieu de partir sur SQlite
J’aimeJ’aime
Je pense que j’avais un soucis au niveau du PATH indiqué !
Depuis que j’ai rectifié, ça renseigne la base SQL.
Par contre, il faudrait maintenant désactiver ls base MySQL pour renvoyer vers sqlite3 et diagnostiquer une éventuelle erreur .
En attendant, je vais pouvoir passer à la suite avec les graphiques.
Un grand merci en attendant.
J’aimeJ’aime
le plus simple pour tester ce backup c’est soit d’arreter MySQL , soit de changer le mot de passe dedans. des que le script ne peux plus écrire dedans , il bascule sur SQlite , et des que MySQL est de nouveau dispo , il recopie les donnees de SQlite dedans puis efface SQlite
J’aimeJ’aime
Je voulais juste dire que aussi bien mysql que sqlite3 fonctionnait maintenant !
J’avais il me semble fait une erreur au niveau de PATH_THERM. Je ne comprends pas et ne suis pas certain que cela bloquait à ce niveau cependant.
En tout cas, tout fonctionne et j’ai même réussi la partie 4 !
Il ne me reste plus qu’à jouer avec tout ça pour bien en comprendre le fonctionnement et ensuite l’adapter à mon usage !
Vraiment encore merci pour ce tuto extra !
J’aimeJ’aime
Merci pour le tuto.
J’ai bien galéré a le mettre en place mais j’ai beaucoup appris
J’aimeJ’aime
Merci pour le tuto.
J’ai deux questions sur la définition de la base de donnée :
– pourquoi mettre un int(11) dans l’id, c’est pour utiliser HighCharts derrière ?
– pourquoi mettre =28 derrière AUTO_INCREMENT ?
merci pour la réponse
J’aimeJ’aime
le int(11) est généré automatiquement par mysql , c’est une valeur par defaut , qui n’a rien a voir avec la taille de l’entier
source : https://www.cloudconnected.fr/2009/04/09/mysql-int11-a-la-meme-taille-que-int3/
le =28 a également été généré automatiquement par mysql , il fait commencer la 1ere ligne au numero 28 , et effectivement c’est inutile. c’est un residu de ma propre base ou j’avais effacé les 27 premieres lignes
j’ai corrigé ça sur la page
J’aimeJ’aime
Merci pour ta réponse si rapide et pour ton wordpress qui m’a permis de passer du json à Mariadb.
Il me reste à trouver comment extraire correctement les données de la db sous php pour générer mon graphique HighCharts
Bonne continuation
J’aimeJ’aime
l’article numero 4 est la pour ca 🙂
https://jahislove314.wordpress.com/2016/02/08/visualisation-des-donnees-sur-une-page-web/
J’aimeJ’aime
Bonjour
I would like to use your program with several « DS18B20 », perhaps 30 or more pieces.
What do I have to change for that?
Adding « sonde4, sonde5, sonde6 … » only returned error messages.
Can you please help me?
J’aimeJ’aime
first you need to modify this lines :
sonde1 = « /sys/bus/w1/devices/w1_bus_master1/28-000005f2424d/w1_slave »
sonde2 = « /sys/bus/w1/devices/w1_bus_master1/28-000005f2764e/w1_slave »
sonde3 = « /sys/bus/w1/devices/w1_bus_master1/28-000005f396a0/w1_slave »
sonde4 = ….. => add a line for each sensor
sondes = [sonde1, sonde2, sonde3, sonde4….] => add a sondeX for each sensor
sonde_value = [0, 0, 0, 0…..] => add a zero for each sensor
after that modify the 2 last lines :
query_db(« » »INSERT INTO PiTemp (date, sonde1, sonde2, sonde3) VALUES (‘%s’,’%s’,’%s’,’%s’) => add a sondeX and a ‘%s’ for each sensor
« » » % (datebuff, sonde_value[0], sonde_value[1], sonde_value[2])) # on INSERT dans la base => add a sonde_value[x] for each sensor
finally go to your database admin tools ( phpmyadmin maybe ?) and add 1 column « sondeX » for each sensor in the table PiTemp
J’aimeJ’aime
Bonjour et respect pour ce tuto bien ficelé,
mon problème: ( sur python 3.4)
2 sondes sont interrogées toutes les 5 s sur une boucle de 10 lectures pour une valeur moyenne plus stable , la boucle se répète toutes les 30s (time.sleep(30)), au bout de 4 à 10 boucles le script plante car les fichiers de lectures (/sys/bus/w1/…. ) ont disparus, après deconnexion du 3,3v et reconnexion je retrouve mes petits.
manifestement quelque chose sature !
as tu rencontré cela ?
J’aimeJ’aime
je ne comprends pas trop tes boucles mais j’ai l’impression que c’est a ce niveau que se situe ton probleme , tu semble avoir 3 boucles (5sec / 10 fois / 30sec) imbriquées les unes dans les autres, et il est possible si tu t’es planté avec ca ,que le nombre de mesure soit tres important . commence par simplifier tes boucles
J’aimeJ’aime
merci de répondre aussi vite!
en effet je regarde de près ces boucles, un test tourne en ce moment avec une seule sonde, mais comme je rencontre d’autres problémes je me demande si mon install est correcte: je bosse avec un B3 comme plateforme de developpemnt avec linterface bureau complet pour mes scripts, ce qui est bien confortable, puis je recopie tout ce petit monde sur des pi0wh qui eux aussi sont en Debian complet , là je pense que se trouverai l’erreur (threadings, interrupts… dus a LDXE). Je te dirai la suite….
J’aimeJ’aime