"Mądrzejszy" dom - RPi oraz DS18B20
Mówimy o "inteligentnych domach". W połączeniu do reszty inteligentnych sprzętów domowych, jak lodówki (wysyłające spam) czy inne czujniki obecności automatycznie włączające światło mają nasze życie ułatwiać lub uprzyjemniać.
Nie mam zamiaru bawić się w aż tak rozbudowane systemy, jakie planują niektórzy. Nie potrzebuję setek rozwiązań i procesora w każdym włączniku ściennym. Ale fajnie jest czasami się nieco pobawić, prawda?
Mam termometr za oknem. Podobnie jak większość osób. Mam jednak termometr elektroniczny z wyświetlaczem ciekłokrystalicznym. Od kiedy jednak kupiłem sobie większy (szerszy) monitor to jest on nieco zasłonięty. Nie było by wygodnie, gdyby obok prognozy pogody na ekranie startowym Windows 8 pojawiała się także faktyczna temperatura w domu, oraz na zewnątrz? O ileż to wygodniejsze rozwiązanie od przesunięcia nieco termometru w lewo, aby go nie zasłaniał monitor! ;‑)
A na serio - czemu się nie pobawić?
Hardware
Mam w domu Raspberry Pi, a nawet dwa. Jeden z nich służy jako serwer i (częściowo) router, ale jego piny GPIO pozostają niewykorzystane, więc można by wykorzystać go do odczytu danych z czujnika temperatury i prezentowania (skoro jest to serwer) w postaci danych do wykorzystania przez inne aplikacje - docelowo, przez aplikację dla Windows 8.
Mam też czujnik DS18B20 z interfejsem 1‑wire, który dość zgrabnie współpracuje z Raspberry Pi. Podłączenie wygląda następująco:
Linia 3,3V podłączona jest do prawej nóżki czujnika. Poprzez rezystor tworzy "pull-up" z linią danych, która jest podłączona do naszego ulubionego pinu GPIO4 oraz środkowej nóżki czujnika. Lewa nóżka podłączona jest do masy. Rezystor według tutoriala na Adafruit powinien być około 4,7 kiloomów, ale równie dobrze poradzi sobie prawie każdy z zakresu od 4,7 kilooma do 10 kiloomów. Ja użyłem 10 kOhm, bo innego nie miałem pod ręką ;‑)
DS18B20 opiera się na 1‑wire, co oznacza, że jest możliwość łączenia wielu takich czujników w łańcuch, a będzie dostęp do wszystkich. Jest też możliwość używania tylko dwóch nóżek ("parasite power"), niestety mój bardzo intensywnie nie chciał z tym współpracować.
Software
Czas na oprogramowanie, część pierwsza. Za komunikację z interfejsem 1‑wire posłużyć mogą nam moduły jądra w1‑gpio oraz w1‑therm, który to umie się komunikować z czujnikiem DS18B20. Ich wymogiem jest m.in. podłączenie właśnie 1‑wire do pinu GPIO4.
Po ich załadowaniu możemy obejrzeć zawartość katalogu /sys/bus/w1/devices, gdzie powinny znaleźć się podkatalogi (linki symboliczne, ale to nieważne) o nazwach w postaci 28‑xxx, gdzie xxx to unikatowy identyfikator czujnika.
sudo modprobe w1-gpio sudo modprobe w1-therm ls /sys/bus/w1/devices
W moim wypadku wynik będzie taki:
[ktos@lily ~]$ ls /sys/bus/w1/devices 28-0000054d332a w1_bus_master1
Z podkatalogu 28‑0000054d332a wypiszmy teraz zawartość pliku w1_slave:
[ktos@lily ~]$ cat /sys/bus/w1/devices/28-0000054d332a/w1_slave 6d 01 4b 46 7f ff 03 10 70 : crc=70 YES 6d 01 4b 46 7f ff 03 10 70 t=22812
Odczyt tego "pliku" trwa chwilkę, ponieważ jest to faktycznie odczyt danych z czujnika. W ostatniej linii mamy t=22812, czyli temperatura wynosi 22,812 stopnia Celsjusza. Szybki rzut oka na dwa termometry, jakie mam na półce i wskazują one 22,0 stopnia oraz 22,8 stopnia. Wychodzi zatem, że słusznie podejrzewałem, że jeden z nich nieźle zaniża.
Przydałoby się, aby moduły jądra były ładowane automatycznie. Używam dystrybucji Arch Linux, i zgodnie z opisem na ArchWiki należy stworzyć plik o rozszerzeniu .conf w katalogu /etc/modules-load.d/. Stworzyłem taki plik:
[ktos@lily ~]$ cat /etc/modules-load.d/w1.conf # ładowanie modułów jądra odpowiedzialnych za 1-wire # i DS18B20 w1-gpio w1-therm
Ok, mamy zatem odczyt temperatury. Szkoda tylko, że nie jest to w najpiękniejszej formie, to raz. Dwa, spróbujmy to "wystawić" na świat.
Stworzyłem testowo malutki skrypt, który pokazuje temperaturę w nieco bardziej "ludzkiej" formie (proszę o wyrozumiałość - nie jestem mistrzem Basha - zapewne da się zrobić lepiej):
#!/bin/sh TEMP=`cat /sys/bus/w1/devices/28-0000054d332a/w1_slave | grep t= | cut -d "=" -f 2` TEMP=`echo "scale=1; $TEMP/1000" | bc` echo "$TEMP°C"
Który po uruchomieniu w konsoli prezentuje nieco bardziej ładną formę temperatury z dokładnością do jednego miejsca po przecinku.
[ktos@lily ~]$ scripts/temperature_ds18b20 22.8°C
W sam raz aby to wykorzystać w innych skryptach, np. po zalogowaniu użytkownika pokazywać mu w terminalu temperaturę z czujnika.
Czyli mamy uruchomiony czujnik temperatury. Gdyby dodać kolejny czujnik, wystarczy połączyć linie zasilania, uziemienia i danych, bez dodatkowego rezystora, a jego identyfikator po chwili pojawi się w odpowiednim katalogu i również będzie można odczytać z niego dane.
W następnej części spróbujemy zbudować aplikację serwerową, która będzie udostępniała dane klientom, np. aplikacji dla Windows 8.