Viena pagrindinių priežasčių, kodėl aš iš viso pirkau RaspberryPi, buvo noras pagaliau prisiversti susidraugauti su linuxu ir kažkiek pramokti python, php, mysql, java, js, ir visokius kitokius šiandien aktualius velnius. Programuoti vien dėl programavimo yra tuščias laiko gaišimas, todėl iš karto reikia daryti kažką naudingo, o ne rašinėti visokius „hello world”. Vos tik nusipirkęs RPI, nusprendžiau pasidaryti kelių zonų termometrą su istorinių duomenų atvaizdavimo galimybe. Tam, kad spyris į užpakalį kažką daryti būtų kuo stipresnis, nusprendžiau viską programuoti pats. Sukurpiau tokį pradinį planą: Cron jobas kas 5 min. paleidžiai Python scriptą, kuris kelis kartus nuskaito DHT22 jutiklio duomenis, juos suvidurkina ir surašo į MySQL DB.
Kaip jau supratot, pasirinkau DHT22 oro temperatūros ir drėgmės jutiklius. Juos pasirinkau dėl pakankamai mažos kainos (~4$ perkant iš AliExpress), paprasto prijungimo (1-wire) ir, žinoma, dėl to, kad jau yra sukurta DHT22 duomenų nuskaitymo RPI biblioteka. Prie RPI DHT22 jutiklius prijungiau pagal viršuje dešinėje pateiktą schemą. Projekte naudoju du DHT22 jutiklius, todėl dėl naudojamos DHT22 duomenų nuskaitymo bibliotekos apribojimų, jutiklius teko prijungti prie atskirtų RPI portų. Vieną iš jutiklių prijungiau prie GPIO19, kitą prie GPIO19. Iš principo, kur juos prijungti, skirtumo nėra. Man šie portai tiesiog buvo fiziškai patogiausi.
Atėjo laikas susidiegti DHT22 nuskaitymo biblioteką. Tam konsolėje įvykdome šią komandą:
git clone git://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code.git
Po to, jau kaip ir galime nuskaityti duomenis:
cd /home/Adafruit-Raspberry-Pi-Python-Code/Adafruit_DHT_Driver sudo ./Adafruit_DHT 22 19
Adafruit_DHT driveris priima du nustatymus: jutiklio versiją (DHT11 ar DHT22) ir porto numerį, prie kurio jutiklis yra prijungtas. Kadangi bandau nuskaityti duomenis iš DHT22 jutiklio, prijungto prie GPIO19 posto, Adafruit_DHT driveriui padaviau šiuos nustatymus: „22 19„. Rezultatas štai toks:
DHT22 yra gan užsispyręs jutiklis, todėl Adafruit_DHT biblioteka ne visuomet sugeba iš jo nuskaityti duomenis. Jei biblioteka negrąžina temperatūros ir santykinės oro drėgmės reikšmių, į jutiklį reikia kreiptis dar bartą. Liuda, bet bent kartą iš penkių jutiklis tikrai negražins mus dominančių duomenų:
Benaršydamas internete, radau, kad Adrafuit_DHT driveris potencialiai gali „pakabinti” visą sistemą. Potenciali bėda slypi šiame nekaltame driverio kodo gabaliukyje, kuris gali netyčia pereiti į amžiną ciklą:
while ( bcm2835_gpio_lev(pin) == 1 ) { usleep(1); }
Protingi žmonės siūlo šią potencialią klaidą taisyti taip:
// wait for pin to drop? int safety = 0; int max_wait = 1000; while ( bcm2835_gpio_lev(pin) == 1 ) { // if no answer, quit if ( safety > max_wait ) { return 2;} usleep(1); safety++; }
Pasiklioviau patarimu ir perkompiliavau Adafruit_DHT driverį. Tiesa, teko kiek pavargti, nes norint perkompiliuoti Adafruit_DHT.c, reikėjo pirma atsisiųsti BCM2835 biblioteką, ją susikompiliuoti ir susidiegti. Taip padariau taip (pagal šį pavyzdį):
cd mkdir -p work/bcm2835 cd work/bcm2835 wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.36.tar.gz tar xvfz bcm2835-1.36.tar.gz cd ./bcm2835-1.36 ./configure make sudo make install
Patį Adafruit_DHT.c perkompiliavau (žinoma, prieš tai atnaujinęs C kodo gabaliuką) su šia komanda:
sudo gcc Adafruit_DHT.c -l bcm2835 -std=gnu99 -o Adafruit_DHT
Na ką, atnaujintas driveris kaip ir veikia. Reikia pasiruošti MySQL duomenų bazę, į kurią rašysim duomenis. Susikūriau MySQL DB pavadinimu „warehouse”, kurioje sukūriau tokią duomenų lentelę:
CREATE TABLE IF NOT EXISTS `duomenys` ( `D_ID` mediumint(9) NOT NULL AUTO_INCREMENT, `D_DATE_CREATED` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `D_ActualDate` datetime DEFAULT NULL, `D_Temperature_1` float DEFAULT NULL, `D_Humidity_1` float DEFAULT NULL, `D_Temperature_2` float DEFAULT NULL, `D_Humidity_2` float DEFAULT NULL, `D_Info` varchar(255) COLLATE utf16_lithuanian_ci DEFAULT NULL, `D_Comments` varchar(255) COLLATE utf16_lithuanian_ci DEFAULT NULL, PRIMARY KEY (`D_ID`) ) ENGINE=InnoDB DEFAULT CHARSET=utf16 COLLATE=utf16_lithuanian_ci AUTO_INCREMENT=48 ;
Pagal kelis internetiniu pavyzdžius sukurpiau šiokį tokį Python skriptą, kuris nuskaito abiejų DHT22 jutiklių duomenis, juos suvidurkina ir kartu su laiko žyme, surašo į prieš tai sukurtą mysql lentelę:
#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb as mdb import sys import arrow import re import subprocess import os import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) ## uses GPIO numbers NOT pin numbers GPIO.setwarnings( False ) GPIO.setup(26, GPIO.OUT) ## 37 PIN / GPIO26 os.chdir(os.path.abspath('/home/python/')) #globals for temperature and humidity averaging temp = 0 hum = 0 def read_dht22 ( PiPin ): success = 0 output = subprocess.check_output(["./Adafruit_DHT", "2302", str(PiPin)]) matches = re.search("Temp =\s+([-+]?[0-9.]+)", output) if (matches): global temp temp = matches.group(1) success = 1 #print temp else: success = 0 #print "fail" matches = re.search("Hum =\s+([0-9.]+)", output) if (matches): global hum hum = matches.group(1) #print hum else: success = 0 #print "fail" return success try: con = mdb.connect('localhost', 'USERNAME', 'PASSWORD', 'warehouse'); cur = con.cursor() cur.execute("SELECT VERSION()") ver = cur.fetchone() sys_date = arrow.now().format('YYYY-MM-DD HH:mm:ss') print "Database version : %s " % ver print sys_date GPIO.output(26,True) #Turn LED ON, while reading DHT2 sensors count_1 = 0 temperature_1 = 0 humidity_1 = 0 for x in range (0, 10): if (read_dht22(19)): count_1 = count_1 + 1 temperature_1 = temperature_1 + float(temp) humidity_1 = humidity_1 + float(hum) #print "[19] Temp: %s Hum: %s Count: %s" %(temp,hum,count_1) else: count_1 = count_1 #print "echem.." if (count_1>0): temperature_1 = round(temperature_1/count_1,1) humidity_1=round(humidity_1/count_1,1) else: count_1=count_1 print "[19] Temperature: %s Humidity: %s" %(temperature_1,humidity_1) count_2 = 0 temperature_2 = 0 humidity_2 = 0 for x in range (0, 10): if (read_dht22(13)): count_2 = count_2 + 1 temperature_2 = temperature_2 + float(temp) humidity_2 = humidity_2 + float(hum) #print "[1] Temp: %s Hum: %s Count: %s" %(temp,hum,count_2) else: count_2 = count_2 #print "echem.." if (count_2>0): temperature_2 = round(temperature_2/count_2,1) humidity_2=round(humidity_2/count_2,1) else: count_2=count_2 print "[13] Temperature: %s Humidity: %s" %(temperature_2,humidity_2) if (count_1 > 0 and count_2 > 0): cur.execute("""INSERT INTO duomenys (D_ActualDate, D_Temperature_1, D_Humidity_1 ,D_Temperature_2, D_Humidity_2, D_Info) VALUES ( %s, %s,%s,%s,%s, 'CronJob')""", [sys_date,temperature_1,humidity_1,temperature_2,humidity_2]) elif (count_1 == 0 and count_2 > 0): cur.execute("""INSERT INTO duomenys (D_ActualDate, D_Temperature_1, D_Humidity_1 ,D_Temperature_2, D_Humidity_2, D_Info) VALUES ( %s, NULL,NULL,%s,%s, 'CronJob')""", [sys_date,temperature_2,humidity_2]) elif (count_1 > 0 and count_2 == 0): cur.execute("""INSERT INTO duomenys (D_ActualDate, D_Temperature_1, D_Humidity_1 ,D_Temperature_2, D_Humidity_2, D_Info) VALUES ( %s,%s,%s,NULL,NULL, 'CronJob')""", [sys_date,temperature_1,humidity_1]) else : cur.execute("""INSERT INTO duomenys (D_ActualDate, D_Temperature_1, D_Humidity_1 ,D_Temperature_2, D_Humidity_2, D_Info) VALUES ( %s, NULL,NULL,NULL,NULL, 'CronJob')""", [sys_date]) con.commit() GPIO.output(26,False) except mdb.Error, e: if con: con.rollback() print "Error %d: %s" % (e.args[0],e.args[1]) sys.exit(1) finally: if con: con.close() GPIO.cleanup()
Tam, kad skriptas veiktų, reikia susidiegti MySQLdb modulį:
sudo apt-get install python-mysqldb
Skripte panaudojau ir Arrow laiko apskaitos biblioteką, kurią taip pat reikia susidiegti:
sudo apt-get install python-setuptools sudo easy_install pip sudo pip install arrow
Beje, nepamirškit skripte nurodyti savo mysql naudotojo vardo ir slaptažodžio 😉
Patogumo dėlei, paruoštą skirptą (jį pavadinau mysql_dht.py) ir perkompiliuotą Adafruit_DHT driverį nukopijavau į /home/python direktoriją. Jei naudojate kitą direktoriją, ją nurodykite skirpto eilutėje „os.chdir(os.path.abspath(‘/home/python/‘))”, kitaip skriptas neveiks.
Ar skriptas veikia, galima pasitikrinti tiesiai iš konsolės:
sudo python /home/python/mysql_dht.py
Turėtumėte gauti tokį rezultatą:
Jeigu gaunate tokią klaidą, įsitikinkite ar Adafruit_DHT driveris yra tikrai toje pačioje direktorijoje, kaip ir pats mysql_dht.py skirptas:
Jei skriptas veikia gerai, galima užkurti automatinį jo vykdymą. Tam panaudojau Cron:
sudo crontab -e
Atsidariusiame lange, pačioje apačioje įrašiau tokią eilutę:
0,5,10,15,20,25,30,35,40,45,50,55 * * * * sudo python /home/python/mysql_dht.py &
Išsaugojus failą, mūsų skriptas bus įvykdomas kas 5 minutes. Simbolis „&” eilutės gale reiškia, kad procesas bus vykdomas fone ir netrukdys sistemos darbui.
Ar Cron jobas veikia, gerai parodo mysql duomenys. Jei duomenys tvarkingai atsigula į nurodytą lentelę, galima eiti gerti kavos 😀
Tinginiams:
Perkompiliuotą Adafruit_DHT driverį ir mano parašyta mysql_dht.py skriptą galite atsisiųsti iš čia: dht22_mysql.zip
Naujausią kodo versiją rasite mano GitHub saugykloje!
[update: 2014-12-04]
Patobulintas duomenų surinkimo kodas: dht22_mysql_2.zip
[update: 2015-01-20]
mysql_dht.py skripte buvo klaida, dėl kurios skirtpas nesugebėdavos „surinkti” neigiamų oro temperatūrų. Klaida buvo šioje kodo eilutėje:
matches = re.search("Temp =\s+([0-9.]+)", output)
Klaidą ištaisiau papildęs re.search išraišką minuso simbolio paieška „[-+]?”:
matches = re.search("Temp =\s+([-+]?[0-9.]+)", output)
Naudinga literatūra:
- http://www.raspipress.com/2012/09/tutorial-install-phpmyadmin-on-your-raspberry-pi
- http://zetcode.com/db/mysqlpython/
- http://www.raspberrypi.org/forums/viewtopic.php?f=32&t=79597
- http://sharedmemorydump.net/post/2013-07-20-adding-a-dht-sensor-to-the-raspberry-pi
- http://sharedmemorydump.net/post/2013-10-16-improvements-to-collection-of-sensor-data
- http://sharedmemorydump.net/post/2013-07-18-logging-data-temperature-with-raspberry-pi
- http://www.anginf.de/?p=286
- http://www.raspberrypi-spy.co.uk/2013/07/running-a-python-script-at-boot-using-cron/
- http://serverfault.com/questions/248305/running-cron-on-every-10-minutes
- http://alvinalexander.com/linux/unix-linux-crontab-every-minute-hour-day-syntax
- http://askubuntu.com/questions/56683/where-is-the-cron-crontab-log
- http://stackoverflow.com/questions/26124363/how-to-keep-run-python-program-in-background-on-raspberry-pi-after-terminate-ssh
- http://stackoverflow.com/questions/24161476/subprocess-popen-simple-code-not-working
Bonus:
Norintiems, bet negalintiems prisijungti prie MySQL DB, kuri sukasi jūsų RPI, siūlau pasiskaityti čia: http://stackoverflow.com/questions/18733802/how-do-i-open-up-my-mysql-on-my-raspberry-pi-for-outside-remote-connections Man padėjo! 😉
Atgalinis pranešimas: Python: Statistinis klaidingų duomenų taškų eliminavimas | Paulius Bautrėnas
Sveikas Pauliau, kaip matau visai neblogai padirbeta, labai issamus tutorialas, didelis dekui Tau. Noriu truputi papildyti, jei turite savo pusltapi, tai galima patalpinti si koda, kad rodytu temperatura uzkrovus puslapi. Aisku, butu galima ir papildyti autorefreshu, bet kadangi nesu rimtas programuotojas, labiau man cia hobis po darbu, gal but kada ir imesiu toki koduka. P.s. skripta bandziau isdestyti pagal tavo Pauliau pateikta pavyzdine duomenu baze ‘warehouse’ ir lentele ‘duomenys’
<?php
error_reporting('E_ALL ^ E_NOTICE');
mysql_connect('localhost','username','password') or die(mysql_error());
mysql_select_db('warehouse') or die(mysql_error());
$page=$_REQUEST['p'];
$limit=1;
if($page=='')
{
$page=1;
$start=0;
}
else
{
$start=$limit*($page-1);
}
$query=mysql_query("select * from duomenys order by D_id desc limit 1;") or die(mysql_error());
$tot=mysql_query("select * from duomenys") or die(mysql_error());
$total=mysql_num_rows($tot);
$num_page=ceil($total/$limit);
echo'Last measurementTempHumidity';
while($res=mysql_fetch_array($query))
{
echo''.$res['D_ActualDate'].' '.$res['D_Temperature_1'].'°C '.$res['D_Humidity_1'].'%';
}
echo'';
?>
kaip matau kodas nusikopijavo nevisai tiksliai, dingo html formatavimas
Esu jau panašiai pasidaręs, tik daug papraščiau.. Nelabai supratau, kam šita vieta:
$tot=mysql_query("select * from duomenys") or die(mysql_error());
$total=mysql_num_rows($tot);
Kam reikia traukti visus duomenis iš DB, norint suskaičiuoti, kiek yra duomenų eulučių? Manau, kad geriau būtų parašyti query, pav. select count(d_id) from warehouse.duomenys ir iškart gauti eilučių skaičių..
Mano trumpat drūtas skriptas atrodo taip:
connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "SELECT d_actualdate, d_temperature_1, d_humidity_1, d_temperature_2, d_humidity_2 from warehouse.duomenys d order by d.d_id desc limit 1";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "
". $row["d_actualdate"]. " - T1: ". $row["d_temperature_1"]. " H1: " . $row["d_humidity_1"]. " - T2: ". $row["d_temperature_2"]. " H2: " . $row["d_humidity_2"]."
";
}
} else {
echo "0 results";
}
$conn->close();
?>
mano mintis buvo narsykleje duomenis patalpinti i lentele, kuri rodo daugiau nei vienos „linijos” istraukima, beje RPi naudoju labiau relems kontroliuoti. Sensoriai tik papildomas pasizaidimas. Tikrai nesigincyju del kodo, jei yra daug paprasteniu budu tam atlikti tai tada liuks :), patirties pasidalijimas visada geras dalykas tobulejimui. Klausimas gal naudoji kazka panausaus i dinamini grafika temperaturai palyginti? kaip tik dabar delioju laisvu laiku. Jei pavyks sekmingai – pasidalinsiu…
Iš principo DHT22 ir jungiau tik su mintimi jų duomenis išsipiešti grafike. Šiaip ne taip surinkau tokį komplikuotą grafiką su „HighCharts”:

Ketinu apie tai artimiausiu metu parašyti postą, bet tikrai būtų pamatyti ir kitas alternatyvas 😉
tau super gavosi :), siaip su tai grafikais tikras galvos skausmas… as bandau su amcharts.com pavyzdziais dirbti, beja sunkiai sekasi 🙂 na nieko dar turiu kantrybes…
Aš tą grafiką prabėgomis gerą mėnesį kūriau ir vis dar tobulinu. Sėkmės su amcharts, nes jie tikrai labai gražiai atrodo. Bus įdomu pamatyti tavo rezultatą.
kaip ir turiu jau padares grafika pagal amchart pavydzi, dar neisbaigtas aisku, nzn kaip i tavo komentaru forma ikelti 🙂 prisegtifile:///home/audrius/Documents/grafikas.jpg
Gaila, bet taip paprastai paveikslėlio čia neįkelsi.. Pirma įkelk paveikslėlį į kokį http://imgur.com ar pan. ir tik tada į komentarą įkelk paveikslėlio nuorodą su atributais „img” 😉
na bandom 🙂
grafikas http://i.imgur.com/7Uf5rD9.jpg
Nice! Labai gražiai atrodo!
ka manai apie sita projektuka, ar verta uzsiimti, gal per daug galvos skausmo http://funofdiy.blogspot.co.uk/2013/10/a-raspberry-pi-controlled-mini-laser.html
Kodėl gi ne. Kuo sudėtingesnis projektas, tuo įdomiau juo užsiimti 😛
Galvoju, kad su dviem skaneriais iseitu daug geresnis projektukas, graviravimo plotas butu lygus 29×29 cm A4 formato lapui, vietoj 4x4cm DVDburnerio… Didziausias issukis tinkamai sukonfiguruoti motor stepperius.
Atgalinis pranešimas: Avietė: DHT22 duomenų atvaizdavimas | Paulius Bautrėnas