Witajcie ! O ile dobrze pamiętam, jakoś przed początkiem ostatniej sesji zimowej, w ramach prokastrynacji, i niechęci do nauki na egzaminy postanowiłem zrobić coś fajnego. Jak pewnie cześć z was widziała na moim fanpage facebookowym, padło na internetowy termometr. O ile skonstruowałem go i on faktycznie działał, o tyle zwój kabli przechodzących przez całe mieszkanie i walający się po moim pokoju wydawał się dość mocno nieestetyczny. Postanowiłem więc odczekać chwilę do momentu, aż będę mieć fundusze na jakieś urządzenie, które pozwoli mi połączyć go z routerem bez kabla biegnącego przez środek mieszkania. Akurat tak się szczęśliwie złożyło, że rodzice rezygnowali akurat z usługi telewizji w Neostradzie, a u nas w domu była ona spięta przez urządzenie, które w ofercie TP widniało wtedy pod nazwą „Live Plug”. Jak to w takich sytuacjach bywa, przechwyciłem nieużywany sprzęt i wykorzystałem go do swoich celów. Powstanie tego zacnego urządzenia zostało zainspirowane artykułem Jakuba Furmana, a wynik działania przekształceń można obserwować tutaj.
Lista potrzebnych rzeczy
Zacznijmy od tego co najważniejsze, czyli od listy rzeczy, która będzie nam potrzebna:
- Płytka prototypowa Arduino (w moim przypadku model Uno R3)
- Płytka stykowa
- Czujnik temperatury DS18B20
- Mikroprocesor (w moim przypadku ATmega model 328-PU)
- Moduł Ethernet ENC28J60
- Rezystor 4,7 k
- Kawałek kabla trójżyłowego o małym przekroju (tak by móc wystawić czujnik na zewnątrz)
- Goldpiny x 3
- Stara taśma IDE (np. od stacji dyskietek), tak aby móc połączyć moduł Ethernet z Arduino/ Atmegą
- Serwera www z obsługą: php, mysql, crontab
Większość tych rzeczy można kupić na przykład na allegro. Od siebie mogę tylko dorzucić uwagę, że warto wybrać czujnik temperatury,który będzie obudowany w kablu i wodoszczelny. Całość przedsięwzięcia (nie licząc arduino, kabelków do podłączenia i płytki stykowej) nie powinna przekroczyć 60zł.
Jeśli chodzi natomiast, o wyświetlanie naszej temperatury gdzieś na stronie www, należałoby jeszcze posiadać serwer do którego można podłączyć się przez ssh, z dostępem do crontab, oraz router, który będzie miał opcję współpracy z serwisem typu no-ip.org.
Schemat i podłączenie
Jeśli kupimy już wszystkie wymagane elementy, można zabrać się za ich podłączenie według tego schematu:
Następnie możemy przesłać na urządzenie kod, który umożliwi nam działanie termometra.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#include "etherShield.h" #include "ETHER_28J60.h" #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 2 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); float temp=-100, // wartość początkowa temperatury unsigned long lastTempRequest = 0; int delayInMillis = 0; static uint8_t mac[6] = {0x54, 0x55, 0x58, 0x10, 0x00, 0x24}; // ustawiamy MAC adres static uint8_t ip[4] = {192, 168, 1, 140}; // ustalamy adres IP pod jakim ma być dostępny program static uint16_t port = 80; ETHER_28J60 e; void setup() { e.setup(mac, ip, port); sensors.begin(); sensors.setWaitForConversion(false); // ustawiamy aby sensory pobierały wartości w tle, nie zawieszając programu sensors.setResolution(12); // ustalamy rozdzielczość pomiaru sensors.requestTemperatures(); // wysyłamy pierwsze żądanie odczytu temperatur delayInMillis = 750 / (1 << (12 - 12)); // wpisujemy czas po jakim żądanie temperatury będzie gotowe do odczytu lastTempRequest = millis(); // ustalamy aktualny czas jako czas ostatniego żądania temperatur } void loop() { char* params; int et,et2; if (millis() - lastTempRequest >= delayInMillis) // czas jaki upłynął jest wystarczający aby wartości były gotowe { temp = sensors.getTempCByIndex(0); // pobranie wartości pierwszego termometru sensors.requestTemperatures(); // wysłanie kolejnego żądania temperatur delayInMillis = 750 / (1 << (12 - 12)); // wpisujemy czas po jakim żądanie temperatury będzie gotowe do odczytu lastTempRequest = millis(); // ustalamy aktualny czas jako czas ostatniego żądania temperatur } if (params = e.serviceRequest()) // obsługa połączenia przychodzącego { if(strcmp(params, "temp_out") == 0) { // żądanie typu http://192.168.1.140/temp_out et = temp*100; // wyświetlenie temperatury bez przecinków e.print(et); // wyplucie wyniku do klienta e.respond(); // wysłanie odpowiedzi } } } } |
Szczególnie ważne są tutaj linijki 16 i 50, gdyż odpowiadają one za adres IP na którym będą widoczne odczytane dane. Zachęcam, aby ustawić go poza pulą serwera DHCP działającego na routerze. Jeśli wszystko działa, możemy przenieść kod na mikroprocesor, na przykład według tego poradnika:
Programowanie Atmega 328-PUA następnie połączyć całość według schematu:
Właściwie na tą chwilę kończymy prace z częścią 'namacalną' naszego projektu. Wystarczy teraz wystawić czujnik za okno, podłączyć moduł pod router i sprawdzić,czy działa na adresie, który wcześniej wpisaliśmy w kod programu. Teraz czas na część 2, czyli udostępnianie wartości odczytanych z termometru w internecie.
Po stronie serwera
Teraz musimy utworzyć sobie konto w serwisie no-ip.org i połączyć je ze swoim routerem (warto szukać opcji Dynamic DNS). Następnie logujemy się na serwer i tworzymy sobie nową bazę danych (logujemy się na nią poprzez polecenie mysql, alternatywnie można też zalogować się do bazy np. z poziomu phpMyAdmin) :
1 2 3 4 5 |
CREATE TABLE IF NOT EXISTS `tpr` ( `time` int(20) unsigned NOT NULL, `temp` float NOT NULL, PRIMARY KEY (`time`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
oraz skrypt, który będzie odpowiedzialny za pobieranie wartości i ich odświeżanie:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php // nawiazujemy polaczenie $connection = @mysql_connect('host', 'nazwa_bazy', 'hasło') // w przypadku niepowodznie wyświetlamy komunikat or die('Brak połączenia z serwerem MySQL.<br />Błąd: '.mysql_error()); // połączenie nawiązane ;-) echo "Udało się połączyć z serwerem!<br />"; // nawiązujemy połączenie z bazą danych $db = @mysql_select_db('nazwa_bazy', $connection) // w przypadku niepowodzenia wyświetlamy komunikat or die('Nie mogę połączyć się z bazą danych<br />Błąd: '.mysql_error()); // połączenie nawiązane ;-) echo "Udało się połączyć z bazą dancych!"; $tpr = file_get_contents('nasz adres z no-ip/temp_out')/100; if(!$tpr) { die; } if($tpr == -100) { die; } $time = time(); mysql_query("INSERT INTO `tpr` SET `time` = '{$time}', `temp` = '{$tpr}'"); // zamykamy połączenie mysql_close($connection); ?> |
Teraz modyfikujemy zmienne w linijkach 3,9 i 15 (wpisujemy adres hosta, nazwę bazy danych i hasło, oraz nasz adres, który wybraliśmy sobie w serwisie no-ip.org). Skrypt zapisujemy z rozszerzeniem .php, i dodajemy do crontab-a poleceniem:
1 |
crontab -e |
taką oto linijkę:
1 |
*/5 * * * * kompletna/sciezka/do/php kompletna/sciezka/do/cron.php |
Na koniec potrzebujemy jeszcze tylko pliku index.php, który będzie odpowiedzialny za wyświetlenie wszystkich danych :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<?php error_reporting(0); mysql_connect('host','nazwabazy','haslo'); mysql_select_db('nazwabazy'); $last = mysql_query("SELECT * FROM `tpr` ORDER BY `time` DESC LIMIT 1"); $l = mysql_fetch_array($last); $temper = $l['temp']; $czas = $l['czas']; ?> <html> <head> <title>Temperatura ;-)</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW"> <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Open+Sans%3A300italic%2C400italic%2C600italic%2C300%2C400%2C600&subset=latin%2Clatin-ext&ver=3.8.1"> </head> <style> body { font-family: 'Open Sans', italic; } </style> <body> <center> <div> <font size = "15" color="black"> <br> <?php echo $temper;?> °C</font></div> <h2>Dane z własnego sensora, odświeżane co 5 minut</h2>& <br> <font size="1">(C) pawelwiejkut.net</font> </center> </body> |
Podsumowując
Jeśli wszystko poszło tak, jak trzeba powinniście mieć teraz przed oczami wynik działania z waszego termometru. Budowa takiego urządzenia nie jest faktycznie do końca prosta, dlatego jeśli coś wam nie poszło, czy jeśli ja gdzieś się pomyliłem – dajcie znać w komentarzach. Mnie osobiście podczas tworzenia artykułu zaciekawił brak wspracia przez fritzing dla części ENC28J60. Nigdzie w internecie nie mogłem jej znaleźć, dlatego też postanowiłem zrobić ją samemu (jest ona wyświetlana poprawnie tylko w opcji „breadboard”). Udostępniam ją do pobrania poniżej, tak samo jak i pliki źródłowe:
Ethernet ENC28j60 Fritzing Part Pliki źródłowe Artykuł bazowy