ok I found my heater controller code.
it is in python with 2 scripts.
The first script LireTemperature.py read the sensor temperature and apply the PID on it.
The calculation returns an amount of time in seconds that the heater element will be ON.
It then it calls another script , in subprocess , to turn ON the heater. This subprocess prevent collision in case the script is start again by the crontab.
The script just do what it does and quit. All the variable are on text file inside a tmpfs folder (a ramdisk) called /ramdisk
This is the LireTemperature script
Code: Select all
#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import os
import sys
import datetime
import subprocess
import shlex
#import RPi.GPIO as GPIO
#lire la date courante
now = datetime.datetime.now()
TARGET = 20.0
PID = 15.0
if (os.path.isfile('/ramdisk/PID.txt')):
f = open('/ramdisk/PID.txt','r')
PID = float(f.readline().strip('\n'))
f.close
else:
if (os.path.isfile('/home/pi/PID.txt')):
os.system('cp /home/pi/PID.txt /ramdisk/PID.txt')
f = open('/ramdisk/PID.txt','r')
PID = float(f.readline().strip('\n'))
f.close
if (os.path.isfile('/ramdisk/TARGET.txt')):
f = open('/ramdisk/TARGET.txt','r')
TARGET = float(f.readline().strip('\n'))
f.close
else:
if (os.path.isfile('/home/pi/TARGET.txt')):
os.system('cp /home/pi/TARGET.txt /ramdisk/TARGET.txt')
f = open('/home/pi/TARGET.txt','r')
TARGET = float(f.readline().strip('\n'))
f.close
#GPIOHeater=23
#GPIO.setmode(GPIO.BCM)
#GPIO.setup(GPIOHeater,GPIO.OUT)
#definition de fonction pour creer un folder
def mkdirp(directory):
if not os.path.isdir(directory):
os.makedirs(directory)
#Fonction pour lire la Température CPU
def LireTarget():
fichier = open("/ramdisk/Target.txt")
texte = fichier.readline()
fichier.close()
return float(texte)
def LireCpu():
fichier = open("/sys/class/thermal/thermal_zone0/temp","r")
texte = fichier.readline()
fichier.close()
return (float(texte)/1000.0)
#Fonction pour lire les Capteurs DS18B20
#P.S. Le crc est vérifier pour être certain
# que la température est valide
# Si après 5 essais non valide,
# la valeur None sera retourné indiquant une erreur
def LireDS18B20( CapteurId):
if CapteurId == None:
return None
Compteur=0
while(1):
try:
fichier = open( "/sys/bus/w1/devices/" + CapteurId + "/w1_slave")
texte = fichier.read()
fichier.close()
ligne1 = texte.split("\n")[0]
crc = ligne1.split("crc=")[1]
if crc.find("YES")>=0:
break;
except:
#ok une erreur, bouclons
pass
Compteur = Compteur + 1
if Compteur >= 5 :
return None
#ok nous avons une température valide
ligne2 = texte.split("\n")[1]
texte_temp = ligne2.split(" ")[9]
return (float(texte_temp[2:])/1000.0)
Capteur1_ID= '28-000004575f0a'
th_t1 = LireDS18B20(Capteur1_ID)
th_target = TARGET
###################// PID here
if th_t1 != None:
Flag = 1
if th_t1 < th_target :
# GPIO.output(GPIOHeater,1)
print("Heater ON")
else:
# GPIO.output(GPIOHeater,1)
Flag=0
print("Heater OFF")
P = (th_target - th_t1) * 10.0
if(P > 40.0):
PID=0
PID = PID + (( th_target - th_t1) * 2.0)
if(PID > 55.0):
PID = 55.0
if(PID < 0.2):
PID = 0.2;
PPID = PID + P
if(PPID > 55.0):
PPID = 55.0
if(PPID < 0.0):
PPID = 0.0
# if Flag == 1:
subprocess.Popen(['sudo','/usr/bin/python','/home/pi/RelayDuration.py',str(PPID)])
lcnow = time.localtime()
FileTemp = "/home/pi/CtrlTemp_" + time.strftime('%d%b%Y',lcnow) + ".txt"
nfile = open(FileTemp,'a')
if nfile != None:
nfile.write(time.strftime('%H:%M:%S') + "\t" + "{:.2f}".format(th_t1) + "\t{:.1f}".format(th_target) + "\t{}".format(PPID) + "\n")
nfile.close()
print("PID={}".format(PID))
f = open("/ramdisk/PID.txt","w")
f.write("{}\n".format(PID))
f.close()
#affichons les valeurs
#petite fonction pour intercepter la valeur None
def TempS(valeur):
if valeur == None :
return "---"
return "{0:.1f}".format(valeur)
print "Temperature Sensor 1: {0}'C Target: {1}'C".format(TempS(th_t1), TempS(th_target))
#ok enregistrons la valeur dans un fichier temporaire pour
#incrustation ultérieur dans le time lapse
#le fichier sera dans le ramdisk folder /temp/temperature.txt
try:
fichier = open("/ramdisk/temperature.txt","w")
fichier.write("{0}\t{1}\t{2}\n".format(now.strftime("%H:%M"),TempS(th_t1), TempS(th_target)))
fichier.close()
except:
pass
#créons le répertoire /media/usbkey/Pi_Temperature
#juste au cas il nâest pas la
FichierRecord = "/home/pi"
mkdirp(FichierRecord)
#Créons le fichier avec la date comme nom
NomTemperature = FichierRecord + "/Temp_" + now.strftime("%Y_%m_%d") + ".txt"
#ouvre fichier en mode append
try:
fichier = open(NomTemperature, "a")
fichier.write("{0}\t{1}\t{2}\n".format(now.strftime("%H:%M"),TempS(th_t1), TempS(th_target)))
fichier.close()
except:
pass
#Créons la page web dynamique
mkdirp("/ramdisk/www")
WebTemperature = "/ramdisk/www/CurrentTemperature.html"
try:
fichier = open(WebTemperature,"w")
fichier.write("<html><head><title>Rpi Temperature</title>")
fichier.write("<meta http-equiv=""refresh"" content=""20"" >")
fichier.write("<style>#cssTable td {text-align:center; vertical-align:middle;padding:10px}</style>")
fichier.write("</head><body>")
fichier.write("<table><tr><td><center><h2>Temperature</h2></td><td width=60></td><td>")
fichier.write("<table border=""2"" id=""cssTable""><tr><td>Sensor</td><td>Target</td></tr>")
fichier.write("<tr><td>{0}°C</td><td>{1}°C</td></tr></table>".format(TempS(th_t1),TempS(th_target)))
fichier.write("</td></tr></table></body></html>")
fichier.close()
except:
pass
#updatons rrdtool
#definissons une fonction
# pour tenir compte d'une valeur invalide
def ValideValeur(valeur):
if valeur == None:
return ":U"
else:
return ":{0:.1f}".format(valeur)
texte= "N" + ValideValeur(th_t1) + ValideValeur(th_target)
#insérons dans le fichier de data rrdtool
fichierRrdtool = "/home/pi/temperatures.rrd"
subprocess.Popen(["/usr/bin/rrdtool","update",fichierRrdtool,texte])
#creons une fonction pour extraire l'information
def rrdExport(debut , step , sortieXML):
texte = "rrdtool xport -s {0} -e now --step {1} ".format(debut, step)
texte += "DEF:a={0}:th_t1:AVERAGE ".format(fichierRrdtool)
texte += "DEF:b={0}:th_target:AVERAGE ".format(fichierRrdtool)
texte += "XPORT:a:""Sensor1"" "
texte += "XPORT:b:""Target"" "
sortie = open("/ramdisk/www/{0}".format(sortieXML),"w")
args = shlex.split(texte)
subprocess.Popen(args, stdout=sortie)
sortie.close()
#ok Extractons les donnés pour 3 heures
rrdExport("now-3h",60, "temperature3h.xml")
#ok Extractons les donnés pour 24 heures
rrdExport("now-24h",180, "temperature24h.xml")
#ok Extractons les donnés pour 48 heures
rrdExport("now-48h",360, "temperature48h.xml")
#ok Extractons les donnés pour 1 semaine
rrdExport("now-8d",7200, "temperature1w.xml")
#ok Extractons les donnés pour 1 mois
rrdExport("now-1month",2880, "temperature1m.xml")
#ok Extractons les donnés pour 3 mois
rrdExport("now-3month",5760, "temperature3m.xml")
#ok Extractons les donnés pour 1 an
rrdExport("now-1y",8640, "temperature1y.xml")
The script to turn the Relay ON. RelayDuration.py
Code: Select all
import sys
import RPi.GPIO as GPIO
import time
GPIOHeater=23
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIOHeater,GPIO.OUT)
print("Argument={}".format(sys.argv[1]))
timeON = float(sys.argv[1])
if timeON >= 0.2 :
GPIO.output(GPIOHeater,1)
time.sleep(timeON)
GPIO.output(GPIOHeater,0)
else:
timeON = 0
file = open("/ramdisk/TimeON.txt","w")
file.write(str(timeON)+"\n")
file.close()
And it's use some text file in the ramdisk folder
/ramdisk/PID.txt => this hold the PID integration variable (this variable is in second).
/ramdisk/TARGET.txt => this is the Target temperature.
And of course I used rrdtool and HighCharts to display the result on the web page.
I did post the way to do it here (HighCharts on a web page).
viewtopic.php?p=672406#p672406
Now crontab.
On the root crontab, (sudo crontab -e), I call the LireTemperature every minutes.
Code: Select all
* * * * * /usr/bin/python /home/pi/LireTemperature.py
On the user crontab , (crontab -e) , I call the crontab when I want to change the target temperature
Code: Select all
30 10 * * * echo "30.0" >/ramdisk/TARGET.txt
00 13 * * * echo "40.0" >/ramdisk/TARGET.txt
00 16 * * * echo "20.0" >/ramdisk/TARGET.txt

- DS18B20_PID_control
- BoxTemp.jpg (38.34 KiB) Viewed 7147 times