Stocker la température dans une base MySQL en Python sur le Raspberry – Partie 3

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

python-logole 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

72 réflexions sur “Stocker la température dans une base MySQL en Python sur le Raspberry – Partie 3

      • 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’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’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’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
        indentation
        par exemple pour la commande if , les 3 lignes suivantes font partie du IF car elle sont indenté par 4 espaces

        J’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 * * *
      crontab

      J’aime

  1. 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’aime

  2. 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’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’aime

  3. 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’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’aime

  4. 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’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’aime

  5. 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’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’aime

  6. 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’aime

  7. 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’aime

  8. 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’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’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’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’aime

  9. 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’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’aime

  10. 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’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 ;

      Aimé 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’aime

  11. 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’aime

  12. 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’aime

  13. 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’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’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’aime

  14. 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’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’aime

  15. 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’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’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’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’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’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’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’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’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’aime

  16. 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’aime

  17. 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’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’aime

  18. 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’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’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’aime

Laisser un commentaire