Raspberry Pi odczyt temperatury przez nodejs

http://raspberrypi.org

W poprzednim wpisie dotyczącym Raspberry Pi pokazałem co należy zrobić aby uruchomić na nim system oraz mini-server www w postaci prostego skryptu nodejs.

RPi nie jest tylko miniaturową wersją zwykłego komputera, na którym można testować aplikacje czy strony www. Do tego można przecież użyć VM (przy tym przydzielić więcej zasobów). Malina ma coś więcej – wbudowany port rozszerzeń GPIO, za pomocą którego możemy wchodzić w interakcje z zewnętrznymi urządzeniami elektronicznymi. Począwszy od prostego świecenia diodami LED, przez odczytywanie wartości z urządzeń aż po bardziej zaawansowane możliwości sterowania.

W tym wpisie pokażę jedną z możliwości – odczyt temperatury z czujnika 1-wire Dallas 18B20.

Aktualizacja systemu

Niestety, w dostępnym w lipcu obrazie Debiana nie było modułu 1-wire, jądro było w wersji 3.1.9.

vokiel@rpi ~$ uname -a
Linux raspberrypi 3.1.9+ #168 PREEMPT Sat Jul 14 18:56:31 BST 2012 armv6l GNU/Linux

Prace przy RPi ciągle trwają, zatem nowe aktualizacje, dodatki pojawiają się bardzo często. W związku z tym potrzebna jest aktualizacja systemu. Dostępnych jest wiele instrukcji, m.in.: http://elinux.org/RPi_Kernel_Compilation, http://www.bootc.net/projects/raspberry-pi-kernel/. Najłatwiejszą wersją (jeśli nie chcecie sami kompilować jądra) jest Hexxeh’s easy updater tool, którego użycie sprowadza się do trzech komend:

wget http://goo.gl/1BOfJ -O /usr/bin/rpi-update && chmod +x /usr/bin/rpi-update
sudo apt-get install ca-certificates
rpi-update 240 #podział pamięci na 240MB CPU / 16MB GPU

Podany sposób nie aktualizuje nam jądra do najnowszej dostępnej wersji, ale jest ona wystarczająca do uruchomienia 1-wire:

vokiel@rpi ~ $ uname -a
Linux rpi 3.2.18+ #20 Mon May 28 17:27:57 EDT 2012 armv6l GNU/Linux

Moduł 1-wire

Wątek na forum RPi dotyczący 1-wire jest dość obszerny: http://www.raspberrypi.org/phpBB3/viewtopic.php?t=6649, ważne jest dla nas jedno – włączenie modułu jądra.

Sprawdźmy najpierw, czy mamy widoczne urządzenie w1 (1-wire):

vokiel@rpi ~ $ ls /sys/bus/
amba  hid  mmc  platform  scsi  sdio  spi  usb

Jak widać nie, zatem musimy dodać moduł, a następnie zrestartować Malinę

root@rpi:~# modprobe w1-gpio

Po restarcie jest ok:

vokiel@rpi ~ $ ls /sys/bus/
amba  hid  mmc  platform  scsi  sdio  spi  usb  w1

Nasz termometr pojawi się w katalogu /sys/bus/w1/devices/ pod swoim id, np.: 28-00000249bf39. Ale aby to się stało, musimy zabrać się za małe lutowanie.

Elektronika

Dallas 18B20

Dallas 18B20

Na zdjęciu obok widać jak wygląda Dallas 18B20. Jest bardzo mały i poręczny, pasuje do miniaturyzacji samego RPi.

Obok zdjęcia widać schemat oznaczenia nóżek: 0V (GND), DQ, V+ – masa, sygnał, zasilanie. Potrzebujemy jeszcze rezystora o oporności 4,7kΩ, który wstawiamy pomiędzy nóżki 2-3.

Przykładowy schemat: (Dla pewności podłączenia sprawdzajcie datasheet producenta.)

http://nathan.chantrell.net/

Do ukończenia zestawu potrzebne będą jeszcze kabelki. Dobrym źródłem może być stary pc, z którego możemy wymonotować taśmy łączące przedni panel z płytą główną. Zaletą takich kabli są gotowe końcówki, które możemy od razu podpinać do pinów GPIO. Przydadzą się jeszcze rurki termokurczliwe, żeby całość nie wyglądała tak tragicznie jak u mnie – izolowanie za pomocą taśmy.

RPI_DS18B20

Jako, że nie jest to blog elektronika, nie będę tu przedstawiał procesu lutowania, w zasadzie nie jest on skomplikowany, ani nawet interesujący. Gotowy zestaw po podłączeniu wygląda następująco:

Podwójna wtyczka (niebieski + szary kabelek) jest podwójna tylko dlatego, że zbrakło mi pojedynczych ;), siwy kabelek jest w tym przypadku niepotrzebny.

Odczyt temperatury

Domyślnie w1-wire dla RPi działa na GPIO4 (pin 7) – niebieski kabelek na zdjęciu powyżej. Proponuję zapoznać się z układem pinów i ich oznaczeniami, wygodny schemat dostępny jest na stronie http://www.raspberrypi-spy.co.uk/2012/06/simple-guide-to-the-rpi-gpio-header-and-pins/. Widoczny na zdjęciu biały kabelek podpięty jest do P1 – zasilanie 3,3V, czarny z tyłu to GND.

Jeśli wszystko zostało podpięte poprawnie, powinniśmy zobaczyć urządzenie w systemie:

vokiel@rpi ~ $ ls -l /sys/bus/w1/devices/
razem 0
lrwxrwxrwx 1 root root 0 wrz 16 08:16 28-00000249bf39 -> ../../../devices/w1_bus_master1/28-00000249bf39
lrwxrwxrwx 1 root root 0 wrz 16 13:04 w1_bus_master1 -> ../../../devices/w1_bus_master1

W katalogu urządzenia zobaczymy kilka plików i katalogów:

vokiel@rpi ~ $ cd /sys/bus/w1/devices/28-00000249bf39
vokiel@rpi /sys/bus/w1/devices/28-00000249bf39 $ ls -la
razem 0
drwxr-xr-x 3 root root    0 wrz 16 08:16 .
drwxr-xr-x 4 root root    0 wrz 16 08:16 ..
lrwxrwxrwx 1 root root    0 wrz 16 13:52 driver -> ../../../bus/w1/drivers/w1_slave_driver
-r--r--r-- 1 root root 4096 wrz 16 13:52 id
-r--r--r-- 1 root root 4096 wrz 16 13:52 name
drwxr-xr-x 2 root root    0 wrz 16 13:52 power
lrwxrwxrwx 1 root root    0 wrz 16 13:52 subsystem -> ../../../bus/w1
-rw-r--r-- 1 root root 4096 wrz 16 13:52 uevent
-r--r--r-- 1 root root 4096 wrz 16 08:16 w1_slave

Najważniejszy dla nas to w1_slave, z którego odczytamy aktualną temperaturę. Możemy to zrobić wykorzystując po prostu program cat:

vokiel@rpi /sys/bus/w1/devices/28-00000249bf39 $ cat w1_slave 
c3 01 4b 46 7f ff 0d 10 2f : crc=2f YES
c3 01 4b 46 7f ff 0d 10 2f t=28187

Jak się nie trudno domyśleć, t=28187 to aktualna temperatura z czujnika (28.187 °C). Oczywiście ta postać nie bardzo nadaje się do dalszego użycia. Sposobów na pobranie temperatury w bardziej czytelnym formacie jest tyle ilu programistów, mój wygląda następująco:

vokiel@rpi /sys/bus/w1/devices/28-00000249bf39 $ \
> cat ./w1_slave | grep t= | cut -f2 -d= | awk '{print $1/1000}'
28.125

Node

Skoro potrafimy już odczytywac temperaturę z czujnika, czas najwyższy połączyć to z nodejs.

Na początek przyda nam się moduł child_process, przy pomocy którego wywołamy sytemową komendę i odbierzemy wynik jej działania.

#!/usr/bin/node
 
var exec = require('child_process').exec;
 
var tempId = '28-00000249bf39',
    dispTempInterval,
    dispTempIntervalClock = 10; //sec
 
var dispTemp = function(){
    exec( "cat /sys/bus/w1/devices/" + tempId + "/w1_slave | grep t= | cut -f2 -d= | awk '{print $1/1000}'", function( error, stdout, stderr ){
        if ( error != null ){
          console.log( "Error: " + error);
        }
 
        var temp = parseFloat(stdout).toFixed(2);
        console.log ( "Current temperature: " + temp + "°C" );
    });
}
 
console.log( 'Started node-temp');
console.log( '-----------------');
 
/* Start interval */
dispTempInterval = setInterval( function(){
  dispTemp();
}, dispTempIntervalClock*1000 );

Uruchamiamy skrypt i co 10 sekund otrzymujemy aktulane odczyty temperatury, które możemy zapisać w bazie danych i zrobić z nich ładny wykres.

Started node-temp
-----------------
Current temperature: 22.50°C
Current temperature: 22.50°C
Current temperature: 24.19°C

Po drobnych modyfikacjach ( github – rpi-node-temp ) efekt wygląda troszeczkę lepiej. Dodałem jeden próg, który oddziela „bezpieczną” temperaturę od krytycznej i odpowiednio sygnalizuje to kolorem. Przyłożenie termometru do czipa pokazuje efekt kolorów:

rpi-node-temp

 

Przeczytaj także

Komentarze: 40

Dodaj komentarz »

 
 
 

Hej właśnie podłączam ten czujnik według twojego opisu i nie pojawia mi się plik w1_slave. Katalog czujnika pojawia się po podłączeniu.

po wykonaniu: #ls /sys/bus/
amba event_source hid i2c mmc platform scsi sdio spi usb w1

 

Odpowiedz

 

Ruszyło dopiero po załadowaniu kolejnego modułu:
modprobe w1-therm

mój system to też rasbian

 

Odpowiedz

 

Proponuję dodanie obu modułów do /etc/modules:

#echo "w1-gpio" >> /etc/modules
#echo "w1-therm" >> /etc/modules

da to pewność, że będą ładowane przy starcie systemu.
AK

 

Odpowiedz

 

@ZuKo dzięki za tip.

Pewnie się przyda, później, bo jeszcze nie restartowałem jeszcze RPi od czasu tego wpisu;)

edit: po restarcie trzeba było dodać oba moduły. Dopisane do /etc/modules, dzięki za komentarze.

 

Odpowiedz

 

Wie ktoś jak to obsłużyć z poziomu C/C++? Coś bardziej eleganckiego niż cat /sys/bus/w1/…

 

Odpowiedz

 

@guzik nie wiem jak odczyt wartości sensora, ale może dasz radę przez obsługę samego GPIO: http://elinux.org/RPi_Low-level_peripherals#GPIO_Driving_Example_.28C.29

 

Odpowiedz

 

Witam, czy nie masz może skryptu do publikowania odczytu temperatury. Może zamiast wysyłania odczytu do konsoli zapis byłby do pliku lub na stronkę web.

 

Odpowiedz

 

Mam prosty skrypt zapisujący odczyty do sqlite3, ale jeszcze wymaga dorpacowania. W najbliższym czasie planuję kolejne wpisy o RPi, więc pewnie niedługo się pojawi.

 

Odpowiedz

 

Witam, mam jeszcze jedno pytanko: co jakiś czas otrzymuje błędny odczyt temperatury np. w pomieszczeniu mam temp. 22.5 C a czasmi mam odczyt na poziomie -0.012 C. Nie wiem z czego to wynika. Masz moze pomysł co może być źle?

 

Odpowiedz

     

    Czasem pojawiają się błędne odczyty, ale zwykle przy nich jest też niepoprawny CRC (pierwsza linia odczytu).

    vokiel@rpi /sys/bus/w1/devices/28-00000249bf39 $ cat w1_slave
    c3 01 4b 46 7f ff 0d 10 2f : crc=2f YES
    c3 01 4b 46 7f ff 0d 10 2f t=28187

    Zatem trzeba przerobić trochę skrypt odczytu, tak aby brał pod uwagę sumę kontrolną i odrzucał wpisy, gdzie jest niepoprawna.

     

    Odpowiedz

 

Hej. Próbowaliście podłączać 2 czujniki do jednego gpio? Mi po podłączeniu zaczęły pojawiać się błędy, że jest niewłaściwe CRC. Otrzymuję coś w rodzaju:

zawsze mam ff na początku, złe crc, ale temperatura jest podawana dobra np. tak jak powyżej wyszłoby 28.187

ff ff ff ff ff ff ff ff ff : crc=2f NO
c3 01 4b 46 7f ff 0d 10 2f t=-0.62

jaką macie wartość w pliku w1_master_pullup?

 

Odpowiedz

 

Błędy mogą wynikać z niewłaściwego pull up . Wartość 4k7 jest dla 5V i przy 1 czujniku pewnie jest OK nawet z napięciem 3V. Przy 3V dałem 3k0 i nie ma problemu z 3 czujnikami.

 

Odpowiedz

 

1) czy mogę zamotować 5 takich czujników ?
2) ile max metrów może mieć kabel łączący gpioczujnik ?

 

Odpowiedz

     

    1. Możesz zamontować tyle czujników ile pinów GPIO zmusisz do obsługi
    2. Testowane przez kumpla na 4m kabla telefonicznego – działa bardzo dobrze. Myślę, że do 10m nie powinno być problemów, powyżej trzeba by policzyć spadki napięcia i rezystancję i ewentualnie skorygować parametry rezystora.

     

    Odpowiedz

       

      podłączyłem 5 czyhbników równolegle z rezystorem 2.5k i wszystko jest ok. Kabele do czujników maja około 4m.

       

      Odpowiedz

       

      podłączyłem 5 czujników równolegle, z 1 rezystorem 2.5k i wszystko jest ok(wykorzystałem 3 piny na gpio). Kabele do czujników maja około 4m.

       

      Odpowiedz

 

Jak zmienić domyślny pin GPIO4(7) na inny ?

 

Odpowiedz

 

chyba „wykorzystując po prostu program cat”

 

Odpowiedz

 

Jako zapalony Arduinowiec już od dawna czaiłem się na zakup rPi, ale cały czas powstrzymywał mnie kompletny brak polskich stron poświęconych początkowym boją z tym maleństwem. Mam nadzieję, że szybko się nie poddasz i będziesz kontynuował swoje dzieło 🙂

Pozdrawiam serdecznie!

 

Odpowiedz

 

Witam, mógłbyś wrzucić schemat podłączenia? Byłbym wdzięczny.

 

Odpowiedz

Raspberry Pi computer
 

I learnt a lot from you guys. Thanks for this discussion.

 

Odpowiedz

 

Hej,

jednak uwaga, w tekscie piszesz opernik 47 Ohm
o oznaczenia wskazują na 4.7 kOhm i tak też na schemacie!
to jest roznica 100x i nie wiem czy czegoś ktoś nie usmaży (chyba nie jak podłączy do 3.3V, ale jakby tak do 5V …)

 

Odpowiedz

 

Super artykuł! Abstrhując od porządnej treści merytorycznej to czytając czułem się jak w latach 80-tych majstrując interfejs oparty o centroniks w oparciu o artykuł z bajtka. Rozumiem, że nodejs to taki dodatkowy bajer, bo odczyt można zrobić z dowolnego języka pozwalającego na dostęp do systemu plików z /sys/bus/w1/devices/ …

 

Odpowiedz

 

Bardzo pomocny artykuł.

Czy próbował ktoś podłączyć do pojedynczego RPi więcej niż jeden taki termometr? Niestety nie udało mi się znaleźć w Sieci opisów takich konstrukcji

 

Odpowiedz

     

    Witam udało się odczytać 9 termometrów, chodziły w miarę stabilnie, długość kabla ok 20mb z jednym rezystorem 4.7 k napięcie 3,3V kabel skrętka kat 5, powyżej tej 20 m lub większej liczbie czujników albo wyświetla czujniki z wartością 0.0 stopnia lub ich nie widzi. Jestem w trakcie prób może na 5 V lub z rezystorem na końcu lini będzie jakaś poprawa.

     

    Odpowiedz

 

Piękna sprawa z tym czujnikiem. A jak zapisywać dane z czujnika do bazy danych? Byłoby o wiele wygodniej z nich korzystać.
Pozdrawiam Autora 🙂

 

Odpowiedz

     

    Najprościej zrobić to chociażby w sqlite3, chociaż do node bardziej by pasował jakiś nosql.

    Tworzenie bazy:

    #!/usr/bin/env node
     
    var sqlite3 = require('sqlite3').verbose();
    var db;
     
    console.log("Creating database temps.sqlite3...");
     
    db = new sqlite3.Database('temps.sqlite3',function(){
        db.run("CREATE TABLE IF NOT EXISTS readings (id INTEGER PRIMARY KEY, term_id TEXT, temperature REAL, timestamp INTEGER)", function(){
            console.log('Database created');
        });
    });
     
    console.log('Done.');

    Odczyt temp z zapisem do bazy:

    #!/usr/bin/env node
     
    var exec = require('child_process').exec
        sqlite3 = require('sqlite3'),
        db = new sqlite3.Database('temps.sqlite3'),
        stmt = db.prepare("INSERT INTO readings (term_id, temperature, timestamp) VALUES(?, ?, ?)");
     
    var tempId = '28-00000249bf39',
        dispTempInterval,
        dispTempIntervalClock = 10; //sec
     
    var dispTemp = function(){
        exec( "cat /sys/bus/w1/devices/" + tempId + "/w1_slave | grep t= | cut -f2 -d= | awk '{print $1/1000}'", function( error, stdout, stderr ){
            if ( error != null ){
              console.log( "Error: " + error);
            }
     
            var temp = parseFloat(stdout).toFixed(2);
            console.log ( "Current temperature: " + temp + "°C" );
     
            var now = Math.round(+new Date()/1000);
     
            stmt.run(tempId, temp, now, function ( err ) {
                if ( err ){
                    console.log('Query error: ' + err);
                }
            });
     
        });
    }
     
    console.log( 'Started node-temp');
    console.log( '-----------------');
     
    /* Start interval */
    dispTempInterval = setInterval( function(){
      dispTemp();
    }, dispTempIntervalClock*1000 );
     

    Odpowiedz

       

      Dzięki za odpowiedź, niestety nie moge poeksperymentować, bo mój termometr się nie pojawia, wygląda to tak:
      pi@raspberrypi ~ $ ls -la /sys/bus/w1/devices/
      razem 0
      drwxr-xr-x 2 root root 0 mar 19 19:13 .
      drwxr-xr-x 4 root root 0 mar 19 19:13 ..
      pi@raspberrypi ~ $
      sprawdzam jeszcze:
      pi@raspberrypi ~ $ ls /sys/bus/
      i mam
      amba container hid mmc sdio w1
      czyli wygląda że dotąd jest ok, połączenia sprawdziłem 10 razy, łącznie z pomiarami napiecia na DS18B20. Szukając przyczyny znalazłem niespójność w schemacie i na zdjęciu. Na chemacie jest podłączone napięcie 5V, a na zdjęciu 3,3V. W necie znalazłem że dla 5V należy zastosować rezystor 4,7kΩ, ale dla 3,3V – 2,7kΩ., Może tu mam przyczynę. Zmieniałem rezystor na 3,67kΩ, potem na 2,8kΩ i nadal nic. Następnym krokiem byłoby podłączenie na 5V z rezystorem 4,7kΩ, ale ponieważ zauważyłem w/w niespójność, a nie chcę zniszczyć malinki pochpnym działaniem (bo nie wiem czy to nie zaszkodzi) wolę się upewnić jak powinno być. Skoro to działa u Ciebie i u wielu innych osób to znaczy że ja coś źle robię, tylko nie wiem co. Proszę o pomoc, pozdrawiam.

       

      Odpowiedz

 

Witam. Jest możliwość wystosowania jakichś alertów np. sms czy mail po przekroczeniu danej wartości? Znaczy na RaspberryPi postawić serwer który to będzie obsługiwał?

 

Odpowiedz

 

Odsyłam tutaj – http://www.ematador.pl/pl/p/Modul-Raspberry-Pi-GPIO-Breakout-40-pin/788
Jak się sprawuje, kto go posiada i czy polecacie? Ewentualnie co innego za podobną kasę?

 

Odpowiedz

 

Dodaj komentarz

 
(nie będzie publikowany)
 
 
Komentarz
 
 

Dozwolone tagi XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
© 2009 - 2023 Vokiel.com
WordPress Theme by Arcsin modified by Vokiel