Raspberry Pi jako system powiadamiania przez SMS
Jakiś czas temu spotkała mnie dość niemiła niespodzianka, wchodzę do jednej z serwerownii, którymi się opiekuje i uderzyła mnie fala gorąca. Klimatyzacja przestała działać, zabezpieczenie nadprądowe klimatyzatora było wyłączone. Podejrzewam je jako winowajcę, mogło się przez te lata już wygrzać i stracić swoje właściwości. Nie mniej jednak udało się je załączyć i klimatyzacja na obiekcie znów zaczęła pracować. Czas, przez który klimatyzacja nie działała nie był długi, żadne z systemów nie wyłączyło się, dlatego nikt nic nie zauważył, że coś jest nie tak. Pomyślałem jednak, że potrzebuje systemu powiadania dzięki czemu będę wiedzieć, że jest problem i trzeba go rozwiązać.
Mógłbym użyć czujnika temperatury wykorzystywanego
w elektronicznych projektach hobbystycznych oraz skorzystać z zakupionego
jakiś czas temu modemu LTE. Na potrzeby tego rozwiązania wykorzystałem
czujnik temperatury DS18B20 podobno bardzo dokładny.
Wykorzystuje on magistralę 1-wire, dzięki czemu za
pomocą jednego przewodu jest w stanie przesłać dane do
Raspberry Pi. Innym czujnikiem jest LM35, wymaga on konwertera
analogowo-cyfrowego i dużo więcej zabawy z lutownicą i programowania a
moje umiejętności elektronicze nie są na najwyższym poziomie. Przy
czujniku DS18B20, jeśli wszystko dobrze podłączymy to temperaturę
można odczytać z pliku za pomocą zwykłego polecenia
cat
.
Czujnik DS18B20 ma trzy wyprowadzenia, jego zasilanie wymaga 3,3V. Jednak aby móc odczytać z niego temperaturę musimy połączyć linię danych z zasilaniem przez rezystor 4,7kΩ. Ja do połączenia wykorzystałem kabel stykowe i wcisnąłem rezystor razem z wyprowadzeniami czujnika i zakleiłem to taśmą izolacyjną z drugiej strony - ze zględu na to, że potrzebujemy pierwszego pinu (zasilania 3,3V), czwartego pinu (pin magistrali 1-wire Raspberry Pi) oraz piątego pinu (masy - GND) wewnętrznego rzędu pinów GPIO Raspberry Pi - zmontowałem sobie taką elegancką wtyczkę uzupełniając przerwę między pinami pustymi plastikowymi wtykami kabeli stykowych i wszystko zakleiłem taśmą izolacyjną, kabel stykowe również dodtakowo zaizolowałem tworząc prowizoryczną sondę.
Oczywiście przed sklejeniem wszystko złożyłem używając płytki prototypowej i przetestowałem. Instalacji RaspiOS oraz jej początkowej konfiguracji nie będę tutaj opisywał. Nie mniej jednak obsługa magistrali 1-wire jest domyśnie wyłączona i należy włączyć przy użyciu narzędzia raspi-config. Z menu wybieramy kolejno:
xf0r3m@sms-alert:~$ sudo raspi-config 5 Interfacing Options -> P7 1-Wire
Potwierdzamy włączenie interfejsu, ze względu na to, że włączyliśmy
sterownik (moduł jądra), przy opuszczaniu programu, będzie on sugerować
potrzebę ponownego uruchamiania. Przystajemy na tę sugestię. Po ponownym
uruchomieniu urządzenia, po wydaniu polecenia
lsmod
, powinniśmy zobaczyć w wierszu
dla modułu wire taki ciąg znaków jak: w1_therm.
xf0r3m@sms-alert:~ $ lsmod ... wire 40960 2 w1_gpio,w1_therm ...
Jeśli nie ma takiego ciągu znaków, oznacza to że urządzenie (czujnik temperatury) nie korzysta z tego modułu, a to oznacza że mamy problemy z komunikacją między czujnikiem a Raspberry Pi. Często powodem takiego działania jest źle dobrany rezystor. Jeśli natomiast czujnik się zgłosił, to możemy przjeść do odczytu temperatury, na ścieżce /sys/bus/w1/devices, możemy znaleźć wszystkie urządzenia podłączone do 1-wire. Magistrala ta wysyła w ramkach unikatowy identyfikator przez co można do niej podłączyć wiele urządzeń. Wspominam o tym dlatego, że katalog przenaczony dla naszego czujnika jest opisany właśnie tym identyfikatorem:
xf0r3m@sms-alert:~ $ ls /sys/bus/w1/devices/ 28-0316850291ff w1_bus_master1
Katalog 28-0316850291ff
jest katalogiem
naszego czujnika, z którego możemy możemy odczytać temperature. Starsze
wersje sterowanika 1-wire umieszczały dane z ramki w pliku
w1_slave i tam możemym odczytać temperaturę w drugiej linii
jako wartość t.
f0r3m@sms-alert:~ $ cat /sys/bus/w1/devices/28-0316850291ff/w1_slave 32 01 4b 46 7f ff 0c 10 8f : crc=8f YES 32 01 4b 46 7f ff 0c 10 8f t=19125
Ta wartość, aby była przydana musi zostać wyłuskana za pomocą dodatkowych poleceń powłoki. Obecnie sterownik umieszcza czysty odczyt temperatury w oddzielnym pliku.
xf0r3m@sms-alert:~ $ cat /sys/bus/w1/devices/28-0316850291ff/temperature 18937
Temperatura podawana jest z dokładnością do części tysięcznej stopnia
celsjusza, aby otrzymać lepiej czytelny dla nas wynik możemy podzielić
wartość zwracaną z czujnika przez 1000, przy użyciu narzędzia
bc, koniecznie z właczoną biblioteką zmiennoprzecinkową
dodaną opcją -l
.
xf0r3m@sms-alert:~ $ echo "$(cat /sys/bus/w1/devices/28-0316850291ff/temperature) / 1000" | bc -l | cut -c 1-6 19.000
Teraz wiedząc jak odczytwać temperaturę, chciałbym ją przesłać do siebie najlepiej z jakimś komunikatem. Oczywistym sposobem przesłanie takich danych może być poczta elektronicza. Jak ze względu na ilość wiadomości jakie już przychodzą na moje skrzynki od różnych systemów, powiadomienia z poczty mam wyłączone, a one i tak mogą zagubić się między innymi wiadomościami. Skuteczne w tym przypadku wydają się wiadomości SMS. Do tego jednak potrzebujemy urządzenia oraz oprogramowania do obsługi sieci komórkowej. Oczywiście tutaj mogłem skorzystać z modułu GSM za parę groszy, ale wolałem skorzystać modemu 4G Huawei. Korzystając z modemu cały backend komunikacji szeregowej z modemem spoczywa na opgramowaniu a nie na mnie (sam bym musiał to pisać, korzystając z poleceń AT) gratis mam połączenie internetowe z dobrą przepustowością.
Do korzystania z modemu LTE, wykorzystamy oprogramowanie ModemManager, które jest już zainstalowane na naszym Raspberry. Po podłączeniu modemu do portu USB, należy wydać następuje polecenie, aby zobaczyć czy nasz modem jest wykrywalny przez ModemManager.
$ mmcli --list-modems /org/freedesktop/ModemManager1/Modem/0 [huawei] E3272
Aby dowiedzieć się wiecej na temat samego połączenia GSM lub czy np. nie trzeba aktywować modemu lub podać numeru PIN, możemy wydać następujące polecenie:
$ mmcli -m 0
To polecenie zwróci nam informacje nt. połączenia GSM.
0
jest indeksem, dzieki któremu możemy
odwołać się do modemu. Uzyskujemy go z poprzedniego polecenia, jest to
ostatni element ścieżki zwróconej przez polecenie.
Obecne karty
SIM, szczególnie te prepaidowe, nie wymagają kodu PIN. Ale
w przypadku kart abonamentowych czy telemetrycznych ten kod może być
wymagany. Wówczas takie połączenie będzie niezarejestrowane
u operatora. Aby odblokować kartę sim należy wydać poniższe polecenie.
$ mmcli -m 0 | grep SIM SIM | path: '/org/freedesktop/ModemManager1/SIM/0' $ mmcli -i 0 --pin=1111 successfully sent PIN code to the SIM
Na początku musimy pobrać indeks karty SIM, następnie odwołując się po przez ten indeks, odblokowujemy kartę SIM podając kod PIN. Tak odblokowana karta powinna się zarejestrować u operatora w ten sposób uzyskaliśmy połączenie GSM. Inna przydatną umiejętnością poza samym wysyłaniem SMS będzie także ich odczyt. Na początku musimy wyświetlić listę otrzymanych SMS, aby poznać ich indeksy.
$ mmcli -m 0 --messaging-list-sms /org/freedesktop/ModemManager1/SMS/1 (received) /org/freedesktop/ModemManager1/SMS/0 (received)
Odczyt wiadomości SMS, realizujemy poprzez poniższe polecenie.
$ mmcli -m 0 --sms 0
To polecenie wyświetli nam szczegóły wiadomości wraz z jej treścia.
Teraz możemy przjeść do wysyłania wiadomości. Pierwszą czynnością jest jej utworzenie. Niestety nie jest to zbyt wygodne, należy jednak pamiętać, że klasyczny SMS ma ograniczenie do 160 znaków, po przekroczeniu tej wartości wiadomość jest dzielona. Nie mniej jednak nie testowałem tego w przypadku modemu. Tak zachowują się telefony. Aby wysłać SMS należy wydać następujące polecenie:
$ mmcli -m 2 --messaging-create-sms="text='Hello, World!',number='+1234567890'" Successfully created new SMS: /org/freedesktop/ModemManager1/SMS/5
Tak utworzonej wiadomości został nadany indeks
5
, odwołując się do wiadomości za pomocą
indeksu wyślemy ją do odbiorcy.
$ mmcli -s 5 --send
Tutaj nie podajemy nawet modemu, ponieważ wszystko jest już zapisane w wiadomości. Wracając jeszcze do poprzedniego polecenia, zwróćmy uwagę w jaki sposób zapisana jest treść wiadomości. Taki sposób nie jest zbyt wygodny dlatego też możemy wysłać za pomocą SMS zawartość pliku, który przekażemy za pomocą ścieżki.
$ mmcli -m 2 --messaging-create-sms="number='+1234567890'" --messaging-create-sms-with-data=temp.txt Successfully created new SMS: /org/freedesktop/ModemManager1/SMS/6 $ mmcli -s 6 --send successfully sent the SMS
Teraz już wiemy w jaki sposób możemy wysłać SMS. Dodatkowo w prosty sposób możemy wykorzystać nasz modem do dodatkowego połączenia z internetem. Wystarczy jedno polecenie, jeśli przyjrzeliśmy się szczegółom dotyczącym modemu, to tam znajduje się również nazwa interfejsu jaki został utworzony w systemie właśnie na potrzeby połączenia z internetem. W przypadku Raspberry Pi jest to wwan0. Jeśli połączenie zostanie zestawione wówczas należy pobrać od operatora adres IP i tak podłączony modem będzie zapeniać dostęp do internetu.
$ mmcli -m 2 --simple-connect="apn=plus" successfully connected the modem $ sudo dhclient wwan0
Polecenie do połączenia internetowego (w przypadku LTE), wymaga nazwy APN, możemy ją znaleźć w recznej konfiguracji transmisji danych dla telefonów komórkowych na stronie swojego operatora. Teraz wiedząc jak odczytywać temperaturę oraz jak wysłać SMS napisałem dwa skrypty, jeden z nich jest uruchamiany przez cron co 5 minut i bada temperaturę jeśli przekroczy ustawioną wartość wówczas uruchomi ten drugi skrypt który wyśle SMS z temperaturą do określonego odbiorcy. Poniżej znajduje się skrypt monitorujący temperature:
#!/bin/bash MAX_TEMP= currentTemp=$(cat /sys/bus/w1/devices/28-0316850291ff/temperature); if [ $currentTemp -ge $MAX_TEMP ]; then /usr/local/bin/send-temperature-alert > /dev/null 2>&1; fi
Skrypt wysyłający powiadomienie SMS:
#!/bin/bash if [ -f /tmp/temp.txt ]; then sudo rm /tmp/temp.txt; fi echo -e "Uwaga! W serwerownii temperatura powietrza wynosi: \ $(echo "$(cat /sys/bus/w1/devices/28-0316850291ff/temperature) / 1000" \ | bc -l \ | cut -c 1-6) oC.\nTa wiadomosc zostala wygenerowana automatycznie prosze na nia nie odpowiadac."\ | sudo tee /tmp/temp.txt > /dev/null 2>&; RECV="" sudo mmcli -s $(basename \ $(sudo mmcli -m 0 --messaging-create-sms="number=\"${RECV}\"" \ --messaging-create-sms-with-data=/tmp/temp.txt | cut -d ":" -f 2)) --send;
Źródła:
~xf0r3m