Jste zde

Webový teploměr

Chtěli by jste webový teploměr, kde je možno připojit několik čidel? Tak tu jste tu správně!

Předem než budete číst tento návod, chci jen upozornit, že zdrojové kódy jsou volně ke stažení. Předpokládám že si je budete měnit dle svých představ, ale myslete na etiku a nevydávejte je za vlastní a nechte v textu odkaz, kde jejste je našli. nař. www.pajkanet.cz. Děkuji.

U měho teploměru jsem kladl důraz na x věcí. Chtěl jsem měřit více čidel najednou, dále jsem chtěl aby to bylo jednoduché, aby si to mohl uděl skoro každý.

Jak to vlastně funguje? Základem všeho je Raspberry pi. Raspberry pi může být těměř jakekoliv. (myslim tím verzi 1.,2. a dnes i 3.) Nároky na hardware jsou téměř minimální. Pojdme dále, níže jsem udělal blokové schéma celého teploměru.

Měření se povádí čidlem DS18B20. Je to čidlo které už z výroby je vykalibrováno a kominukuje po jednom drátě tzv. 1-wire. Cena čidla se pohybuje kolem 50kč. Čidlo potřebuje k provozu 3 dráty.

Maximální délku drátu Vám neřeknu a mě to funguje na UTP drát dlouhý něco přes 40-50m. 

  P_20160611_114631_0.jpgP_20160611_114650_0.jpg

Tento drát pak přiveden na převodník napětí.  - viz. http://www.pajkanet.cz/?q=prevodnikurovne

Ten má zaúkol ne jen převést napětí z 5V na 3,3V ale hlavně chrání raspberry pi před napěťovými špičkami a statickou elektrikou. 

Převodník je velice jednoduchý je tvořen tranzistorem MOSFET a v podstatě se přenaší datově jen log.0. - Celý modul se na aukro da pořidit za pár korun. Navíc tento modul obsahuje 4 vstupy. Takže mám plany ho využit i na oddělenou komunikaci přes I2C.  

Export3.png

Pak je tento převodník napojený do raspberry pi. Ten přimo využívá rozhraní 1-wire. Co 5min spouští script v pythonu. Script načte teplotu a uloží je do tabáze. Databáze je typu MySQL. A zde nastává zlomový okamžik. Neboť ja jsem chtěl aby teploměr byl univerzální.tzn. mít několik raspberry pi - různě po okolí - světě. (chata, garáž). Každé raspberry pi si měřilo teplotu a ukládalo centrálně do databáze. Pak je možné vyčítat z databáze více čidel najednou. Ale také jsem chtěl aby vše šlo udělat na jednom raspberry pi. Jenže tím se mi to celé zkomplikovalo. MySQL defaultně a na hostovaných webech (aspoň předpokládám) mají zakázane přímé propojení (port 3306). Nezbývalo nic jineho než to celé trochu jinak obejít. Proto script v raspberry pi využívá http protokolu, který se přpipojí na server. Na serveru, kde běží web server je speciální stránka v php, tam se předá informace jako je teplota a ID čida (ID - identifikační čislo možná volba od 0 - 999). A samozřejmě heslo pro ukládání. - to jen aby nějaký vtipálek negeneroval teploty.. :-) PHP stránka se localně pak připojí do Mysql a teplotu do ní uloží.

Zde je naukázku výpis v phpmyadminu jak je to uloženo v databázi.

phpadmin.png

vidíte že v databázi už mám přes 110tis záznamu. - jedno čidlo mi už teplotu zapisuje od roku 2014. Chystám se dělat ještě graf, ale zatím to mám jen rozdělané. Také krásně jde vidět IDcidla 51 -mám bazen a IDcidla 123 je na jiném raspberry pi.

Pak už jen stačí najet na stránku kde je teploměr a přes php načtu hodnotu z databáze a pomcí knihovny na kreslení v php načtu prázdný obrázek a jen dokreslím hodnoty.

Prázdný obrázek:

Export2_0_0.png

Tak toto byl stručný úvod. Pojdme už na programy a scripty.

  Raspberry pi není dnes snad už představovat. Kdo se v elektronice trochu orientuje uřčitě o něm u slyšel. Takže pokud mate koupené raspberry pi a nachystanou flashku dnes už minimálně 8GB stačí stahnout ze stranek tzv.NOOBS LITE.  Je to pár souborů které nahrají na flash disk. Ten pak nastartuje jako by instalační menu. Připomínám, že raspberry pi musí být na připojené na internet. Neboť právě odtud bude stahovat instalačku raspbianu. Je to jen pár klikanců označit raspbian a dát instalovat a vše už si dělá samo.

Po instalaci raspberry pi se pripojte pomocí druhého PC přes ssh (např. program putty). IP adresu si zjistěte na routeru. Uživ. jméno je: "pi" a heslo: "raspberry". Samozřejmě můžete pracovat přímo na raspberry pi. Ale pokud budete mít raspberry pi model B, věřte tomu, že práce není tak moc efektivní, neboť v grafickém rozhraní je raspberry pi dost pomalé. Navíc přes putty můžete lechce kopírovat příkazy.

Takže pokud se přihlasíte měli byjste vidět něco podobného:

 

putty1.png    

  Dále pak zadejte příkaz: 

sudo nano /boot/config.txt

Otevře se soubor a vy tam jen zadejte tento řádek:

dtoverlay=w1-gpio,gpiopin=4

a příkazem ctrl+x program opuste a uložte změny.

Nyní můžete raspberry pi vypnout a zapojit čidla dle schématu:

zapojeni_0.png

Zapojení jsem si vypujčil od : http://projects.privateeyepi.com/home/temperature-sensor-project-using-d...

Ale i tak na netu je toho mraky. Ja tam sice mám ještě prevodník úrovně, ale nyní na princip není potřeba.

Nyní opět můžeme zapnout raspbery pi. Po nastartovaní a přihlášení přes ssh napíšeme tento příkaz:

ls /sys/bus/w1/devices/

 

cidla.png

Vidíme že na sbernici máme dvě čidla. Nyní si zkusíme vypsat teplotu jedno z nich pomocí příkazu:

cat /sys/bus/w1/devices/28-03146c9956ff/w1_slave

a dostaneme:

cidla2.png

t=20437 znamená, že teplota je 20,4 °C. Je také důležité si všimnout CRC (tzv. kontrolní součet). Pokud je YES komunikace s čidle proběhla v pořádku.

Tak pokud jste se dostali až jsem a vše Vám funguje můžeme (teplota se měří) přejít na script. - ve scriptu jsou měřené dvě čidla.

pomoci příkazu: 

sudo nano mereni_teploty.py

vytvoříme soubor a do něho vložíme nasledující script. Tento script jsem našel někde na netu a jen jsem si trochu upravil.

 

pi@raspberrypi:~ $ cat mereni_teploty.py
import requests
#import hashlib  -nebude potreba nesifruji...
import time

#Dont forget to fill in PASSWORD and URL TO saveTemp (twice) in this file

sensorids = ["28-03146c8eedff","28-03146c9956ff"]
avgtemperatures = []
for sensor in range(len(sensorids)):
        temperatures = []
        for polltime in range(0,3):
                text = '';
                while text.split("\n")[0].find("YES") == -1:
                        # Open the file that we viewed earlier so that python can see what is in it. Replace the serial number as before.
                        tfile = open("/sys/bus/w1/devices/"+ sensorids[sensor] +"/w1_slave")
                        # Read all of the text in the file.
                        text = tfile.read()
                        # Close the file now that the text has been read.
                        tfile.close()
                        time.sleep(1)

                # Split the text with new lines (\n) and select the second line.
                secondline = text.split("\n")[1]
                # Split the line into words, referring to the spaces, and select the 10th word (counting from 0).
                temperaturedata = secondline.split(" ")[9]
                # The first two characters are "t=", so get rid of those and convert the temperature from a string to a number.
                temperature = float(temperaturedata[2:])
                # Put the decimal point in the right place and display it.
                temperatures.append(temperature / 1000)

        avgtemperatures.append(sum(temperatures) / float(len(temperatures)))

print avgtemperatures[0]
print avgtemperatures[1]

session = requests.Session()
pozdrav = session.get(url='http://tvoje.domena.cz/saveTemp.php?step=pozdrav').text
print pozdrav

post_data = {'IDcidla':'50', 'teplota':avgtemperatures[0],'heslo':'tvojeheslo','poznamka':'prizemnicidlo'}
post_request = session.post(url='http://tvoje.domen.cz/teplomer/saveTemp.php',data=post_data)
post_data = {'IDcidla':'51', 'teplota':avgtemperatures[1],'heslo':'tvojeheslo','poznamka':'bazen'}
post_request = session.post(url='http://tvoje.domena.cz/teplomer/saveTemp.php',data=post_data)

if post_request.status_code == 200 :
        print post_request.text

 Nesmíte zapomenout přiřadit ve scriptu správné ID čidel ("28-03146c8eedff") a pak taky heslo a tvoji adresu stránek. (v připadě provozu webu přímo na raspberry staci místo tvoje .domena.cz dát je local).  

Na script pak spustite prikazem 

 python mereni_teploty.py

 

a dostaneme:

cidla3.png

A nakonec přidáme script do cronu aby co 5min se spouštěl a zapisoval teplotu.

sudo crontab -e

 

a zapíšeme tam tento řádek:

*/5 * * * * /usr/bin/python /home/pi/mereni_teploty.py

A tímto mámé stranu na raspberry pi hotovou.

Nyní nás čeká webserver.

Na připravený web server si uděláme php soubor s názvem saveTemp.php. Např.dobrý editor je PSpad  a do něho uložíme tyto řádky:

<?php

// ver.0.9
//  6.9.2014
// Pajka 
// program na pridani udaju do databaze...
// Prosim nastavte si svoje heslo ktere je potreba nastavit i do raspberry pi.
// upoyornuji ze kominukace neni sifrovana - neposilaji se cenna data.. - neni potreba

/*
-----------------------------------------------------------------------------
-- Struktura tabulky `teplota`
--

CREATE TABLE IF NOT EXISTS `teplota` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `IDcidla` int(11) NOT NULL,
  `cas` datetime NOT NULL,
  `teplota` double NOT NULL,
  `poznamka` varchar(32) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-------------------------------------------------------------------------------
*/

define("PASSWORD","tvojeheslo");    // slouzi k zabezpeceni komunikace mezi raspberry pi a MySQLi serverem

//*************************** udaje pro MySQLi **************************************
define("SERVER","localhost");
define("USERNAME","mereni");
define("PASSWORDMYSQL","hesloMysql"); 
define("DATABAZE","mereni");
//************************************************************************************
  
session_start();
    $mysqli = initDB();
    if(isset($_GET['step']) && $_GET['step'] == 'pozdrav') 
  {
        posliPozdrav();    // posle pozdrav pro raspberry - test pro raspberry a nebo moznost budouci kominikace....
    }
   else if (isset($_POST['IDcidla']) && isset($_POST['teplota']) && isset($_POST['heslo']) && isset($_POST['poznamka'])) 
   {
          vlozdoDatabaze($mysqli);
      } 

    /* close connection */
  $mysqli->close();  
// konec programu

//-----------------------------------------------------------------------------------

function initDB()
 {
  $mysqli = new mysqli(SERVER, USERNAME , PASSWORDMYSQL , DATABAZE);
  /* check connection */
  if (mysqli_connect_errno())
  {
   printf("Connect failed: %s\n", mysqli_connect_error());
   exit();
  }
     return $mysqli;
 }

function posliPozdrav() 
  {
        $_SESSION['tempPozdrav'] ='Ahoj jsem pripraven na prijmuti teploty';
        echo $_SESSION['tempPozdrav'];
    }

function vlozdoDatabaze($mysqli)
 {
  $IDcidla = intval($_POST['IDcidla'] ); 
  $teplota = floatval($_POST['teplota']);
  $heslo = strval($_POST['heslo']);
  $poznamka = strval($_POST['poznamka']);
  
  if ($heslo == PASSWORD) 
   {
    $stmt = $mysqli->prepare("INSERT INTO teplota (IDcidla, cas, teplota , poznamka ) VALUES (?, ?, ?, ?)");
    $stmt->bind_param('isds',$IDcidla,$cas ,$teplota, $poznamka);
 
    $cas = date("Y-m-d H:i:s");

    /* execute prepared statement */
    $stmt->execute();
    printf("%d Row inserted.\n", $stmt->affected_rows);  
   }
   else
   {
    echo "Spatne heslo";
   }

  /* close statement and connection */
  $stmt->close();
 }
 
?>

a uložíme tento soubor. Pak pokud mate webserver a mysql datazi, určitě i používate phpmyadmina. Přes něho se přihlaste a musíte vytvořit databazi s jménem "mereni". - Pak vlož tabulku pres SQL-  je tam přimo kolonka na SQL příkaz a tam vlož:

-- Struktura tabulky `teplota`
--

CREATE TABLE IF NOT EXISTS `teplota` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `IDcidla` int(11) NOT NULL,
  `cas` datetime NOT NULL,
  `teplota` double NOT NULL,
  `poznamka` varchar(32) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

nyní máme vytvořenou databazi "mereni" a tabulku se jménem "teplota". Dále máme už udělaný script v raspberry pi, který komunikuje se scriptem na webu pomci saveTemp.php takže bychom měli pres phpadmina vidět jestli se tabulka teploty plní.

A už se blížíme do finále.

Opet vytvoříme v PSpadu soubor s názvem index.php a do něho vložíme:

<html>
<head>
<title>Teploměr od Pajky :-)</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1250">
</head>
<body>
<?php
 session_start();
// error_reporting(E_ALL);
require "./scripty/databaze.php";
 
    $mysqli = pripojeni_Mysql();                                   //pripojeni k databazi
  $query = "SELECT * FROM teplota WHERE `IDcidla` =123 ORDER BY id DESC  LIMIT 1 ";     //vyber posledni vlozene teploty

 if ($result = mysqli_query($mysqli, $query))
  {
   /* fetch associative array */
   while ($row = mysqli_fetch_row($result)) 
   {
    // printf (" Cas: %s teplota: %s\n", $row[2], $row[3]);
     $akt_teplota = $row[3];
     $datumacas = strtotime($row[2]);
     $datumacas=StrFTime("%d.%m.%Y  %H:%M",$datumacas);   
   }
   $akt_teplota = number_format($akt_teplota, 1, ',', ' ');
  }
 
  $query = "SELECT * FROM teplota WHERE `IDcidla` =51 ORDER BY id DESC  LIMIT 1 ";     //vyber posledni vlozene teploty

 if ($result = mysqli_query($mysqli, $query))
  {
   /* fetch associative array */
   while ($row = mysqli_fetch_row($result)) 
   {
    // printf (" Cas: %s teplota: %s\n", $row[2], $row[3]);
     $bazen_teplota = $row[3];
   }
   $bazen_teplota = number_format($bazen_teplota, 1, ',', ' ');
  }  
 
  $query = "SELECT * FROM teplota WHERE `IDcidla` =50 ORDER BY id DESC  LIMIT 1 ";     //vyber posledni vlozene teploty
  
 if ($result = mysqli_query($mysqli, $query))
  {
   /* fetch associative array */
   while ($row = mysqli_fetch_row($result)) 
   {
    // printf (" Cas: %s teplota: %s\n", $row[2], $row[3]);
     $priz_teplota = $row[3];
   }
   $priz_teplota = number_format($priz_teplota, 1, ',', ' ');
  }    

  //minimalni nebo maximalni hodnota jde si myslim urcovat i jinym zpusobem jak mam zde.   SELECT cas,MAX(teplota) FROM teplota WHERE cas >= CURDATE()
  // ale pozor pak sloupecek cas nam neukazuje spravny cas!! (viz. Agregační funkce) - i kdyz v nasem obrazku neni cas potreba presto jsem volil tento sql, kdybych v budoucnu chtel cas pouzit.

  $query = "SELECT cas,teplota FROM teplota WHERE `IDcidla` =123 AND cas >= CURDATE() ORDER BY teplota ASC LIMIT 1";    //min. teplota dne.
  if ($result = mysqli_query($mysqli, $query))
  {
   while ( $row = mysqli_fetch_row($result))
   {
    $min_teplota = $row[1];
    $min_teplota = number_format($min_teplota, 1, ',', ' ');
    $min_cas =strtotime( $row[0]);
    $min_cas=StrFTime("%H:%M",$min_cas);
//    echo "<br/> Minimalni teplota byla: $min_teplota °C v $min_cas <br/> " ;
   } 
  }
  
  $query = "SELECT cas,teplota FROM teplota WHERE  `IDcidla` =123 AND cas >= CURDATE() ORDER BY teplota DESC LIMIT 1";    //max. teplota dne.
  if ($result = mysqli_query($mysqli, $query))
  {
   while ( $row = mysqli_fetch_row($result))
   {
    $max_teplota = $row[1];
    $max_teplota = number_format($max_teplota, 1, ',', ' ');
    $max_cas =strtotime( $row[0]);
    $max_cas=StrFTime("%H:%M",$max_cas);
//   echo "<br/> Maximalni teplota byla: $max_teplota °C v $max_cas <br/> " ;
   }
  }  
  mysqli_free_result($result);
  Close_Mysql($mysqli);                                       // ukonceni spojeni k databazi

 // Kresleni obrazku
  $obrazek = imagecreatefrompng("teplomer_raw.png");                //nacte obrazek 
  $modra = imagecolorallocate($obrazek,0,0,255);
  $cervena = imagecolorallocate($obrazek,255,0,0);
  $hneda = imagecolorallocate($obrazek,128,0,0);
  $zelena = imagecolorallocate($obrazek,0,128,0);
  $cerna = imagecolorallocate($obrazek,0,0,0);

//  imagestring($obrazek,12,30,240," 11,5°C",$modra);          // aktualni hodnota teploty
  imagettftext($obrazek, 26, 0, 75, 75, $hneda, 'arial.ttf', "Vzduch:");    // umistneni
  imagettftext($obrazek, 50, 0, 75, 150, $hneda, 'arial.ttf', $akt_teplota."°C");    // aktualni hodnota teploty
  imagettftext($obrazek, 18, 0, 75, 190, $zelena, 'arial.ttf', $datumacas);    // datum

  
  imagettftext($obrazek, 26, 0, 800, 350, $modra, 'arial.ttf', "Voda:");    // umistneni
  imagettftext($obrazek, 50, 0, 800, 420, $modra, 'arial.ttf',  $bazen_teplota."°C");    // teplota vody
 
  imagettftext($obrazek,14,0,800,470,$cervena,'arial.ttf',"Max.".$max_teplota."°C v  ".$max_cas." hod.");          // max. hodnota dne.
  imagettftext($obrazek,14,0,800,495,$modra,'arial.ttf',"Min.".$min_teplota."°C  v  ".$min_cas." hod.");          // min. hodnota dne. 
  
  imagettftext($obrazek, 18, 0, 800, 550, $hneda, 'arial.ttf', "www.pajkanet.cz");    // reklama  
  imagettftext($obrazek, 12, 0, 780, 580, $zelena, 'arial.ttf', "Teplota prizemniho cidla: ".$priz_teplota."°C");    // prizemni cidlo

  imagepng($obrazek,'teplomer_akt.png');
  imagedestroy($obrazek); 
 // print_r(error_get_last());
 ?>
<img src="teplomer_akt.png" alt="teplomer">
<br>
</body>

</html>

 Samozřejme je potřeba jede soubor, který slouží k připojení k databázi a ten je ve složce /scripty a s názvem "databaze.php" - výpis:

<?php
 // pripojeni k databazi
 // ip , user , password , databaze , port 
function pripojeni_Mysql()
{
 $db_spojeni = mysqli_connect('localhost','mereni','heslodomysql','mereni', 3306);
 
 //otestovani jestli se podarilo spojeni
 if ($db_spojeni)
  {
 //  echo 'Pripojeni se podarilo';
  }
  else
   {
    echo 'Pripojeni se nezdarilo';
    echo '<br />';
    echo 'Popis chyby: '. mysqli_connect_error();
    exit();   
   }
  return $db_spojeni;   
}

function Close_Mysql($db_spojeni)
{
 // Odpojeni od databaze
 if ($db_spojeni) mysqli_close($db_spojeni); 
}
?>

 A to je skoro konec. Jen chybí do složky, kde mame index.php vložit tzv. surovy obrazek s jménem  "teplomer_raw" a je to hotové.

Tady přidávám jěšte odkaz, kde si to můžete všechny soubory stáhnout. - (musím je jeste ale nyni vytvorit).

Konec. 

Omouvám se všem prográmátorům, pokud uvidí nějaké funkce složité a přitom by třeba šli vyřešit lépe. Nejsem žadný extra programátor, jen je to můj koníček a vše dělám při chvilkách po večerech. Pokud budete mít někdo nějaké připomínky tak prosím napište.

Pajka :-)