Depuis 2015, j'utilise ma petite framboise pour réguler ma chaudière au fioul, je vais vous présenter mon projet ici et donner mes codes sources pour aider des personnes qui voudraient ce lancer dans un projets similaire
Je suis conscient qu'il y a beaucoup de chose que l'on peut améliorer, optimiser dans ce projet, mais je le fait avec mes connaissances et sur mon temps libre, d'ailleurs je l'améliore un peu chaque année
Partie 1 :
Mon matériel : (principal)
1) Raspberry pi 2
2) Une sonde de température DS18B20 (1wire)
3) Une carte 2 relais TOR
Système d'exploitation :
2015-05-05-raspbian-wheezy
Langage de programmation utilisé :
- Python
- PHP
Serveur WEB :
Apache
Base de donnée :
MySQL
Voici le squelette du programme, écrit en Python :
Code : Tout sélectionner
#!/usr/bin/python
# -*- coding: utf8 -*-
import os
import glob
import time
import datetime
import MySQLdb
import RPi.GPIO as GPIO # bibliothèque pour utiliser les GPIO
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
SEUIL_DE_SECU = 22.0 #Seuil max de gestion de la température
SEUIL = 19.5 #Seuil réglé
DELTA = 0.5 #Delta qui permet de réguler la température afin d'éviter un déclenchement intempestive.
ETAT_REGULATION = 0 # 0 chauffage à l'arrêt / 1 chauffage en marche
# a adapter a la configuration
RELAIS_1 = 20
RELAIS_2 = 21
LEDverte = 17
LEDrouge = 22
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28-0115524b7dff')[0]
device_file = device_folder + '/w1_slave'
GPIO.setmode(GPIO.BCM) # mode de numérotation des pins
GPIO.setup(LEDverte,GPIO.OUT) #Declaration de la pin en sortie
GPIO.setup(LEDrouge,GPIO.OUT)
GPIO.setup(RELAIS_1,GPIO.OUT)
GPIO.setup(RELAIS_2,GPIO.OUT)
#Valeurs initiales
GPIO.output(LEDverte,GPIO.LOW)
GPIO.output(RELAIS_1,GPIO.HIGH)
def read_temp_raw():
f = open(device_file, 'r')
lines = f.readlines()
f.close()
return lines
def read_temp():
lines = read_temp_raw()
while lines[0].strip()[-3:] != 'YES':
time.sleep(0.2)
lines = read_temp_raw()
equals_pos = lines[1].find('t=')
if equals_pos != -1:
temp_string = lines[1][equals_pos+2:]
temp_c = float(temp_string) / 1000.0
return temp_c
def reguation(SEUIL_DE_SECU, SEUIL, DELTA, ETAT_REGULATION):
if SEUIL >= SEUIL_DE_SECU:
SEUIL = SEUIL_DE_SECU
if (TEMPERATURE >= SEUIL_DE_SECU):
return 0
if (TEMPERATURE <= (SEUIL - DELTA) and ETAT_REGULATION == 0):
return 1
if (TEMPERATURE >= (SEUIL + DELTA) and ETAT_REGULATION == 1):
return 0
if ETAT_REGULATION == 0:
return 0
if ETAT_REGULATION == 1:
return 1
while True:
TEMPERATURE = read_temp()
TEMPERATURE = float (TEMPERATURE)
DATE = time.strftime('%Y-%m-%d %H:%M:%S') #formating date for mySQL
print DATE, "-> ", TEMPERATURE, "°C"
#Connection à la base de données "temperature" pour enregistrer les températures
try:
db = MySQLdb.connect(host="127.0.0.1", user="XXXX", passwd="XXXXXXXX", db="Raspberry_pi")
except Exception:
print "Erreur connexion MySQL en 127.0.0.1"
else:
cur = db.cursor()
cur.execute("INSERT INTO temperature (date, temperature) VALUES (%s, %s)", (DATE, TEMPERATURE))
db.commit()
db.close()
#Connection à la base de données "regulation" pour récupérer le seuil de régulation
try:
db = MySQLdb.connect(host="127.0.0.1", user="XXXX", passwd="XXXXXXXX", db="Raspberry_pi")
except Exception:
print "Erreur connexion MySQL en 127.0.0.1"
else:
cur = db.cursor()
cur.execute("select regulation from regulation where date < %s order by date desc",(DATE, )) #Je récupère la valeur de régulation depuis la base régulation classé selon toute les date inférieur à l'actuel par ordre décroissant.
SEUIL_temp=cur.fetchone()
SEUIL=SEUIL_temp[0] #La valeur récupéré est un tulpe, je selectionne donc la 1ère valeur de mon tulpe qui ne contient qu'une valeur
SEUIL = float (SEUIL)
print "Le seuil à réguler est de :", SEUIL, "°C"
db.commit()
db.close()
ETAT_REGULATION=reguation(SEUIL_DE_SECU, SEUIL, DELTA, ETAT_REGULATION)
if ETAT_REGULATION == 1:
GPIO.output(LEDverte,GPIO.HIGH)
GPIO.output(RELAIS_1,GPIO.LOW)
try:
db = MySQLdb.connect(host="127.0.0.1", user="XXXX", passwd="XXXXXXXX", db="Raspberry_pi")
except Exception:
print "Erreur connexion MySQL en 127.0.0.1"
else:
cur = db.cursor()
cur.execute("select temps_de_fonctionnement from compteur where id=2")
TEMPS_DE_FONCTIONNEMENT_temp=cur.fetchone()
TEMPS_DE_FONCTIONNEMENT=STEMPS_DE_FONCTIONNEMENT_temp[0]
TEMPS_DE_FONCTIONNEMENT=STEMPS_DE_FONCTIONNEMENT+10
cur.execute("UPDATE compteur SET temps_de_fonctionnement=%s WHERE id=2", (TEMPS_DE_FONCTIONNEMENT))
db.commit()
db.close()
if ETAT_REGULATION == 0:
GPIO.output(LEDverte,GPIO.LOW)
GPIO.output(RELAIS_1,GPIO.HIGH)
time.sleep(599)
Déjà, j'initialise mes valeurs initiales et définit mes ports sur le GPIO du Raspberry PI. (Un œil averti verra que je déclare 2 sorties pour la carte relais et que j'en utilise qu'une et une sortie pour une LED rouge que je n'utilise pas non plus, pour le moment ...)
J'ai une fonction qui me permet de récupérer la température par la sonde DS18B20, une fonction qui gère la régulation de manière très simple avec un hystérésis.
Le programme tourne dans une boucle sans fin, toute les 10 minutes, il va récupérer la température et la date (et l'heure) de la prise de mesure et l'afficher dans la console Python ainsi que le seuil de régularisation désiré.
La valeur de la température de régularisation et récupéré dans une base de donnée, elle est sélectionnée en fonction de la date et l'heure d'exécution du programme.
Lorsque la température mesurée est en dessous du seuil de déclenchement, j'active la sortie de mon relais (et j'allume la LED verte).
J'en profite pour enregistrer dans une autre base de données le temps de fonctionnement de la chaudière.
Partie 2 :
Le reste de l'interface ce fait par des pages WEB :
La 1ère me permet de visualiser les températures sur la journée :
Code : Tout sélectionner
<div id="corps">
<h1>Température</h1>
<canvas id = "schema" height="600" width="576" style="border:1px solid">
Votre navigateur ne supporte pas la balise canvas
</canvas>
<script>
var zone_dessin = document.getElementById("schema");
var graphe= zone_dessin.getContext("2d");
graphe.strokeStyle = "#0098f8";
graphe.lineWidth=2;
graphe.beginPath(); // Début du chemin
graphe.moveTo(0,600); // Le tracé part du point 0,600
<?php
try
{
// On se connecte à MySQL
$bdd = new PDO('mysql:host=localhost;dbname=Raspberry_pi;charset=utf8', 'XXXX', 'XXXXXXXX');
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}
$long_tab=0;
date_default_timezone_set('UTC');
$Debut = date ("Y-m-d");
$Fin = date("Y-m-d", strtotime("+1 day"));
$reponse = $bdd->query('SELECT * FROM temperature WHERE date BETWEEN "' . $Debut .'" AND"' . $Fin. '"');
$espacement=0;
//creation des points pour le tracage de la courbe
$reponse = $bdd->query('SELECT * FROM temperature WHERE date BETWEEN "' . $Debut .'" AND"' . $Fin. '"');
while ($donnees = $reponse->fetch())
{
$temperature=$donnees['temperature'];
$temperature2=600-($temperature*15);?>
graphe.lineTo(<?php echo $espacement; ?>,<?php echo $temperature2; ?>);<?php
$espacement=$espacement+4;
}
$reponse->closeCursor();
?>
graphe.stroke();
</script>
<?php
try
{
// On se connecte à MySQL
$bdd = new PDO('mysql:host=localhost;dbname=Raspberry_pi;charset=utf8', 'XXXX', 'XXXXXXXXX');
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}
// Si tout va bien, on peut continuer
$reponse = $bdd->query('SELECT * FROM temperature ORDER BY id DESC');
$donnees = $reponse->fetch();
$date=$donnees['date'];
$temperature=$donnees['temperature'];
echo '<br />La dernière mesure de température à été faite le : ' . $date . '<br />La température mesurée était de : ' . $temperature .'°C';
$reponse = $bdd->query('SELECT temperature, date FROM temperature ORDER BY temperature DESC, date ASC'); //tri température décroissant
$donnees = $reponse->fetch();
$date=$donnees['date'];
$temperature=$donnees['temperature'];
echo '<br /><br />La température la plus haute à été mesurée le : ' . $date . '<br />La température mesurée était de : ' . $temperature .'°C';
$reponse = $bdd->query('SELECT temperature, date FROM temperature ORDER BY temperature ASC, date ASC');
$donnees = $reponse->fetch();
$date=$donnees['date'];
$temperature=$donnees['temperature'];
echo '<br /><br />La température la plus basse à été mesurée le : ' . $date . '<br />La température mesurée était de : ' . $temperature .'°C';
$reponse->closeCursor();
?>
<p>
Pour consulter des valeurs sur une plage de temps cliquez ici : <a href="raspberry_temp.php">Plage de température</a>
</p>
</div>
Je renvoie également la dernière mesure de température effectuée ainsi que l'heure de mesure, cela me permet de savoir si le programme python tourne toujours.
Pour information, j'affiche la dernière température minimum et maximum mesurée.
Si j'ai besoin d'analyser l'évolution de la température sur une durée déterminé, je me rends sur cette page :
Code : Tout sélectionner
<div id="corps">
<h1>Température</h1>
<p>
Inserez une date de début et de fin sous le format suivant : YYYY-MM-JJ HH:MM:SS
</p>
<form action="raspberry_temp2.php" method="post">
<p>
Date de début : <input type="text" name="Debut" />
Date de fin : <input type="text" name="Fin" />
<br /><input type="submit" value="Valider" />
</p>
</form>
</div>
<div id="pied_de_page">
Code : Tout sélectionner
<div id="corps">
<h1>Température</h1>
<canvas id = "schema" height="600" width="700" style="border:1px solid">
Votre navigateur ne supporte pas la balise canvas
</canvas>
<script>
var zone_dessin = document.getElementById("schema");
var graphe= zone_dessin.getContext("2d");
graphe.strokeStyle = "#0098f8";
graphe.lineWidth=2;
//graphe.strokeRect(20, 50, 220,200);
graphe.beginPath(); // Début du chemin
graphe.moveTo(0,600); // Le tracé part du point 50,50
//graphe.stroke();
//graphe.moveTo(100,120);
<?php
if (isset($_POST['Debut'])!= false AND isset($_POST['Fin'])!= false) //Il y a donc des informations des renseigné
{
$Debut=$_POST['Debut'];
$Fin=$_POST['Fin'];
if ($Debut!=NULL AND $Fin!=NULL)
{
try
{
// On se connecte à MySQL
$bdd = new PDO('mysql:host=localhost;dbname=Raspberry_pi;charset=utf8', 'XXXX', 'XXXXXXXX');
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}
// Si tout va bien, on peut continuer
$Debut=htmlspecialchars($_POST['Debut']);
$Fin=htmlspecialchars($_POST['Fin']);
$long_tab=0;
$reponse = $bdd->query('SELECT * FROM temperature WHERE date BETWEEN "' . $Debut .'" AND"' . $Fin. '"');
//calcul de la taille du tableau
while ($donnees = $reponse->fetch())
{
$long_tab=$long_tab+1;
}
$espacement=(int)(700/$long_tab); // calcul de l'espacement pour tracer la courbe
$espacement_val=$espacement;
//creation des points pour le tracage de la courbe
$reponse = $bdd->query('SELECT * FROM temperature WHERE date BETWEEN "' . $Debut .'" AND"' . $Fin. '"');
while ($donnees = $reponse->fetch())
{
$temperature=$donnees['temperature'];
$temperature2=600-($temperature*15);?>
graphe.lineTo(<?php echo $espacement; ?>,<?php echo $temperature2; ?>);<?php
$espacement=$espacement+$espacement_val;
}
?>
graphe.stroke();
</script>
<?php
$reponse = $bdd->query('SELECT * FROM temperature WHERE date BETWEEN "' . $Debut .'" AND"' . $Fin. '"');
while ($donnees = $reponse->fetch())
{
$date=$donnees['date'];
$temperature=$donnees['temperature'];
echo 'Le ' . $date . ' la température était de : ' . $temperature . '°C<br />';
}
$reponse->closeCursor();
}
}
else
{
echo "Vous n'avez pas saisie de valeur !";
}
?>
<p>
Pour consulter des valeurs sur une plage de temps cliquez ici : <a href="raspberry_temp.php">Plage de température</a>
</p>
</div>
Mais il me sort très bien la plage de valeurs désiré.
L'affichage des valeurs c'est bien, maintenant place aux consignes de régulations (celle que l'on récupère dans le programme en python) :
Code : Tout sélectionner
<div id="corps">
<h1>Gestion de la régulation</h1>
<h2>Insertion d'une nouvelle règle de régulation</h2>
<p>
Pour insérer une nouvelle règle de régulation, remplir le formulaire suivant :
<form action="regulation_2.php" method="post">
<p>
Date de début : <input type="text" name="Debut" />
Seuil : <input type="text" name="Seuil" />
<br /><input type="submit" value="Valider" />
</p>
</form>
<h2>Visualisation des règles de régulation</h2>
<table>
<tr>
<th>Date</th>
<th>Seuil de température</th>
</tr>
<?php
try
{
// On se connecte à MySQL
$bdd = new PDO('mysql:host=localhost;dbname=Raspberry_pi;charset=utf8', 'XXXX', 'XXXXXXXX');
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}
// Si tout va bien, on peut continuer
$reponse = $bdd->query("SELECT * FROM regulation ORDER BY date ASC"); // Requête SQL
while ($donnees = $reponse->fetch())
{
?>
<p>
<tr>
<?php $id_bdd=$donnees['id'];
$date=$donnees['date'];
$date=stripslashes($date); //enlève les slashes rajouter précédemment
echo '<td>';
echo $date;
echo '</td>';
$regulation=$donnees['regulation'];
$regulation=stripslashes($regulation); //enlève les slashes rajouter précédemment
echo '<td>';
echo $regulation;
echo "°C";
echo '</td>';
?>
</tr>
</p>
<?php
}
?>
</table>
<h2>Temps de fonctionnement hiver 2017</h2>
<?php
$reponse = $bdd->query('SELECT * FROM compteur WHERE id=2');
$donnees = $reponse->fetch();
$temps=$donnees['temps_de_fonctionnement'];
$jour = $temps / 60 / 24;
$jour = (int) $jour;
$heure = $temps / 60 % 24;
$heure = (int) $heure;
$minute = $temps % 60;
$minute = (int) $minute;
echo 'La chaudière a tourné pendant : '. $jour.' jours '. $heure.' heures et '. $minute.' minutes';
?>
<h2>Temps de fonctionnement hiver 2015-2016</h2>
<?php
$reponse = $bdd->query('SELECT * FROM compteur WHERE id=1');
$donnees = $reponse->fetch();
$temps=$donnees['temps_de_fonctionnement'];
$jour = $temps / 60 / 24;
$jour = (int) $jour;
$heure = $temps / 60 % 24;
$heure = (int) $heure;
$minute = $temps % 60;
$minute = (int) $minute;
echo 'La chaudière a tourné pendant : '. $jour.' jours '. $heure.' heures et '. $minute.' minutes';
$reponse->closeCursor(); // Termine le traitement de la requête
?>
</div>
(Là encore, une amélioration serait à apporter, il me manque la suppression des règles )
En bonus, j'affiche mes compteurs de temps de fonctionnement ( amélioration à faire : gestion automatique)
Voici l'autre morceau du code qui ajoute les règles de régulation dans la base de donnée :
Code : Tout sélectionner
<div id="corps">
<h1>Gestion de la régulation</h1>
<?php
if (isset($_POST['Debut'])!= false AND isset($_POST['Seuil'])!= false) //Il y a donc des informations des renseigné
{
$Debut=$_POST['Debut'];
$Seuil=$_POST['Seuil'];
if ($Debut!=NULL AND $Seuil!=NULL)
{
try
{
// On se connecte à MySQL
$bdd = new PDO('mysql:host=localhost;dbname=Raspberry_pi;charset=utf8', 'XXXX', 'XXXXXXXX');
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}
// Si tout va bien, on peut continuer
$date=htmlspecialchars($_POST['Debut']);
$regulation=htmlspecialchars($_POST['Seuil']);
$regulation=floatval($regulation);
echo $date;
echo "<br />";
echo $regulation;
echo "°C";
$bdd->exec("INSERT INTO regulation VALUES('', '$date', '$regulation')");
//$bdd->closeCursor();
}
}
else
{
echo "Vous n'avez pas saisie de valeur !";
}
?>
<p>
Si pas de message d'erreur, les valeurs ont bien été enregistré !
</p>
</div>
Code : Tout sélectionner
<div id="corps">
<h1>Estimation du niveau de la cuve</h1>
<?php
try
{
// On se connecte à MySQL
$bdd = new PDO('mysql:host=localhost;dbname=Raspberry_pi;charset=utf8', 'XXXX', 'XXXXXXXX');
}
catch(Exception $e)
{
// En cas d'erreur, on affiche un message et on arrête tout
die('Erreur : '.$e->getMessage());
}
// Si tout va bien, on peut continuer
$reponse = $bdd->query('SELECT * FROM compteur WHERE id=2');
$donnees = $reponse->fetch();
$temps=$donnees['temps_de_fonctionnement'];
$pourcent_consomme=$temps*100/68510;
$pourcent_consomme=round($pourcent_consomme, 2);
$pourcent_restant=100-$pourcent_consomme;
$pourcent_consomme2=(int) $pourcent_consomme;
$litre_restant=$pourcent_restant*1200/100;
echo 'Il reste environ '. $pourcent_restant.' % de fioul dans la cuve soit approximativement '. $litre_restant. ' litres.';
echo "<br />";
$reponse->closeCursor(); // Termine le traitement de la requête
?>
<canvas id = "schema" height="100" width="8" style="border:2px solid">
Votre navigateur ne supporte pas la balise canvas
</canvas>
<script>
var zone_dessin = document.getElementById("schema");
var graphe= zone_dessin.getContext("2d");
graphe.strokeStyle = "#ff0000";
graphe.lineWidth=8;
graphe.beginPath(); // Début du chemin
graphe.moveTo(4,100); // Le tracé part du point 2,0
graphe.lineTo(4,<?php echo $pourcent_consomme2; ?>);
graphe.stroke();
</script>
</div>
Voilà ou j'en suis pour le moment, je pense qu'a partir des informations fournit, vous avez aussi les moyen de vous amuser avec votre framboise.