Bot SMS pod Linuksem

Ostatnio w firmie pojawił się temat stworzenia SMS bota. Zacząłem więc szukać rozwiązań. Jeden z pomysłów, to postawienienie komputera z Linuksem na pokładzie, podłączenie do niego telefonu z ofertą, w której jest miliard darmowych SMS-ów i uruchomienie czegoś magicznego, co zajmie się odbieraniem i wysyłaniem wiadomości. I to magiczne coś właśnie zamierzam opisać.

Rozwiązanie które można zastosować, okazało się prostsze niż myślałem. Można użyć do tego świetnego programu, który jest dostępny zarówno pod Linuksem jak i Windowsem - mowa o Gammu. Jest to program, który komunikuje się z telefonem, lub modemem i służy do różnego rodzaju cznności, takich jak odbieranie/wysyłanie SMS-ów, zarządzanie kontaktami, zadaniami, kalenarzem itp. Ja oczywiście skupię się na odbieraniu i wysyłaniu SMS-ów.

Tak więc do komunikacji użytkownika z botem posłużę się Gammu - to już ustaliliśmy. Żeby było ciekawiej, Gammu posiada demona do wysyłania i odbierania SMS-ów - gammu-smsd. Jako backend do przechowywania danych można użyć zwykłych plików lub bazy danych (obsługiwany jest MySQL, PostgreSQL i SQLite). Pliki odradzam, bo to nieco ogranicza funkcjonalność - przykładowo nie jest możliwe wysyłanie wiadomości przy użyciu polecenia gammu-smsd-inject lub nie można przekazać żadnego id wiadomości do skryptu, który można uruchomić po otrzymaniu wiadomości (o tym w dalszej części). Lepiej zatem skorzystać z bazy danych. Ja wybrałem PostgreSQL.

Konfiguracja Gammu oraz SMSD

Najpierw trzeba zacząć od komunikacji Gammu z telefonem. Mój telefon to Sony Ericsson k800i. Pomijam fakt, że trzeba podłączyć telefon do komputera przez kabel USB ;) Poniżej zamieszczam źródła plików konfiguracyjnych:

~/.gammurc

[gammu] 
port = /dev/ttyACM0 
model = 
connection = at19200 
synchronizetime = no 
logfile = 
logformat = errorsdate 
use_locking = 
gammuloc =

/etc/gammu_smsdrc

[gammu] 
port = /dev/ttyACM0 
model = 
connection = at19200 
synchronizetime = no 
logfile = 
logformat = errorsdate 
use_locking = 
gammuloc = 

[smsd] 
Service = pgsql 
LogFile = syslog 
DebugLevel = 255 
DeliveryReport = log 
RunOnReceive = /home/jaro/bin/sms_trigger.py 
User = uzytkownik_bazy 
Password = haslo_bazy 
PC = localhost 
Database = gammu

Poprawność konfiguracji połączenia z telefonem można sprawdzić przez polecenie gammu identify. U mnie wyjście wyglądało tak:

# gammu identify 
Manufacturer : Sony Ericsson 
Model : K800i (AAD-3022031-BV) 
Firmware : R8BF003 080130 2133 CXC1250212_ORANGE_WI 
IMEI : WOLE_NIE_POKAZYWAĆ 
Kod produktu : AAD-3022031-BV 
SIM IMSI : WOLE_NIE_POKAZYWAĆ

Przed uruchomieniem demona smsd, trzeba utworzyć odpowiednie tabele w bazie danych. W dokumentacji znajduje się przykładowy plik ze skryptem SQL, który tworzy te tabele. U mnie znajduje się on w lokalizacji: /usr/share/doc/gammu/examples/sql/pgsql.sql Wystarczy uruchomić skrypt i voila!

Skrypt (bot)

W pliku gammu_smsdrc jest opcja RunOnReceive, która, jak się można domyślić, wskazuje skrypt uruchamiany po odebraniu wiadomości. Skrypt jest uruchamiany z parametrem, który zawiera id wiersza w bazie danych w tabeli inbox. Wiersz zawiera dane przesłanej wiadomości. Napisałem w Pythonie przykładowy skrypt, który odczytuje odebraną wiadomość, sprawdza jaki tekst wysłano i na jego podstawie wysyła odpowiedź.

#!/usr/bin/python

import psycopg2 as db, sys, os

db_user = 'nazwa_uzytkownika'
db_password = 'haslo_do_bazy'
db_host = 'localhost'
db_name = 'gammu'


def main(argv=None):
        try:
                sms_id = sys.argv[1]
        except IndexError:
                print 'Za malo parametrow'
                sys.exit()
        
        try:
                conn = db.connect("dbname=%s user=%s password=%s host=%s" % (db_name, db_user, db_password, db_host))
        except:
                print 'Blad podczas polaczenia z baza'
                
        if not sms_id.isdigit():
                print 'Niepoprawny parametr'
                sys.exit()
        
        cur = conn.cursor()
        cur.execute("SELECT * FROM inbox WHERE id=%s" % sms_id)
        
        row = cur.fetchone()
        
        if not row:
                print 'Nie znaleziono wiadomosci sms o podanym id'
                sys.exit()
                
                
        rcp_num = row[3]
        command = row[8].strip().lower()
        
        if command == 'jezyk':
                response = "Python"
        elif command == 'system':
                response = "Linux"
        else:
                response = "Nieznana komenda"
        
        
        os.system("gammu-smsd-inject TEXT %s -text '%s'" % (rcp_num, response)) 
        


if __name__ == '__main__':
        main()
        

Finał - uruchomienie demona

Wreszcie przechodzimy do puenty - uruchomienia demona. Wystarczy krótkie:

gammu-smsd --daemon

I w ten oto sposób, telefon jest gotowy do odbierania i wysyłania wiadomości.

Internet przez komórkę pod Linuxem

Zazwyczaj jak korzystam z Internetu na laptopie, to albo w domu, albo gdzieś gdzie jest sieć bezprzewodowa. Czasami jednak pojawiają się sytuacje, w których potrzebuję dostępu do Internetu w miejscach, w których nie łapię żadnej sieci bezprzewodowej i nie ma gdzie się wpiąć kablem. Z pomocą przychodzi GPRS.

Co jest potrzebne żeby uruchomić GPRS pod Linuxem:

  1. telefon, który obsługuje tę technologię komunikacyjną
  2. włączoną opcję połączeń z Internetem przez kabel USB (w SE k800i ustawienia->łączność->USB->Włącz)
  3. kabel do telefonu lub blutetooth (przez IrDA chyba też się da)
  4. skompilowany i załadowany moduł jądra do obsługi modemów przez USB (USB_ACM)
  5. program global 3g

Modem w jajku

Po podłączeniu telefonu do komputera przez kabel, w katalogu /dev, powinny znajdować się pliki ACM*. Jeżeli są, to znaczy że moduł USB_ACM jest załadowany. W przeciwnym wypadku, najpierw można spróbować załadować go ręcznie (być może z jakiegoś powodu nie powiodło się automatyczne ładowanie):

# modprobe cdc_acm

Jeżeli to nie pomogło, to trzeba skompilować moduł USB_ACM. Nie będę opisywał szczegółowo jak to się robi, bo to temat na osobny wpis. W Internecie jest dużo informacji o kompilacji jądra. Podpowiem tylko gdzie i jakiej opcji w menu konfiguracyjnym trzeba szukać:

Location:
    -> Device Drivers
      -> USB Support
        -> Support for Host-side USB 
          -> USB Modem (CDC ACM) support

Po skompilowaniu modułu, powinien on automatycznie ładować się gdy telefon zostanie podłączony do komputera.

Połączenie ze światem

Czas na punkt kulminacyjny. Do połączenia użyłem świetnego programu Global 3G Jego wielkimi zaletami są wbudowane ustawienia do najpopularniejszych operatorów sieci komórkowych (w tym także polskich) oraz sterowniki do wielu telefonów. W konfiguracji programu wybrałem swojego operatora z listy dostawców, natomiast z listy urządzeń odpowiedni telefon. Posiadam Sony Ericsson k800i, który widnieje na liście obsługiwanych urządzeń, ale jak go wybrałem, to nie łączył się z Internetem. Dopiero jak wybrałem opcję "Sony Ericsson - Standard Models (2)", to zadziałało. W przypadku połączenia telefonu przez kabel, jako port trzeba wybrać USB -> ACM0 lub ACM1 jeżeli nie zadziała. Piszę tylko o kablu, bo nie próbowałem łączyć się przez blutetooth.

To by było na tyle jeśli chodzi o konfigurację. Wystarczy kliknąć "połącz" i wrota Internetu otworzą się przed nami. Wolnego, bo wolnego, ale w sytuacji awaryjnej wystarczy. Polecam wyłączyć w przeglądarce pobieranie obrazków, animacji, javascriptu i apletów javy. Niestety jest jeden szkopuł. Global 3G w darmowej wersji przed nawiązaniem połączenia z Internetem, zmusza nas do odczekania 6 minut (tylko za pierwszym razem w ciągu pojedynczego uruchomienia programu) i nie pamięta konfiguracji. Jeżeli chcemy pozbyć się tej uciążliwości, to trzeba zakupić od autora płatną wersję za 29 zł. Wydaje mi się, ze nie są to duże pieniądze i czuję, że fajnie jest zapłacić komuś drobną kwotę za dobrze wykonaną robotę.

Mobilność jest ekstra

Ostatnio przedłużyłem umowę z Orange i dzięki temu za jedyne 19 zł zakupiłem Sony Ericssona k800i. Wcześniej posiadałem (podobno kultowego) NEC-a e616v, który jest już trochę stary, ale cenię go za łatwość obsługi i solidność wykonania. Niemniej jednak miał trochę ograniczeń, typu mało funkcjonalny bluetooth, który służył tylko do obsługi bezprzewodowej słuchawki, czy MIDP niby w wersji 2.0, ale musiałem sporo nakombinować się, żeby zainstalować na nim jakieś aplikacje. Jak już jakąś udało się zainstalować, to zazwyczaj w wersji okrojonej.

Przy wyborze telefonu istotna dla mnie była obsługa protokołu SyncML, ponieważ potrzebuję możliwości synchronizacji Kalendarza Google z kalendarzem w telefonie. Oprócz tego dzięki temu protokołowi można eksportować na serwer kontakty, zadania i notatki. Ogólnie przydatne przy zmianie telefonu, albo po prostu jako backup.

Aplikacje które zainstalowałem

  • Fotokody - program do obsługi fotokodów
  • Gmail - klient poczty Gmail
  • Google Maps - z ciekawszych możliwości, to pokazywanie aktualnej lokalizacji, nawet jeżeli telefon nie posiada GPS-a
  • MidpSSH - klient SSH i Telnet
  • Opera Mini - mobilna wersja świetnej przeglądarki internetowej. Z powodzeniem zastępuje wbudowaną w telefon przeglądarkę stron WWW
  • Talkonaut - aplikacja umożliwia dzwonienie przez VoIP, korzystając z EDGE, 3G, WIFI. Ja używam go jako klienta Jabbera.
  • Wordmax - mobilny słownik Polsko-Angielski i Angielsko-Polski

Synchronizacja z Google Calendar

Niestety sam Google Calendar jeszcze nie umożliwia synchronizacji z innymi urządzeniami niż BlackBerry, iPhone i telefony z Windows Mobile. Musiałem więc szukać innych rozwiązań. Najpierw natknąłem się na GooSync. Początkowo wszystko działało jak należy, ale po około tygoniu postanowiłem szukać czegoś innego, bo, krótko mówiąc, przestało działać. Wybór padł na Schedule World, który oprócz kalendarza, umożliwia synchronizację zadań, notatek i książki adresowej. Możliwa jest także synchronizacja kontaktów z Gmaila. Życie stało się łatwiejsze, odkąd swój kalendarz mam w kieszeni i mogę dodawać wydarzenia zarówno przy pomocy komputera jak i telefonu.

Podsumowując, mobilność jest ekstra - mogę szybko zorientować się gdzie jestem przy pomocy Google Maps, sprawdzić pocztę wszędzie gdzie jest zasięg GPRS, sprawdzać rozkłady jazdy autobusów i pociągów przy pomocy Opery Mini. Nasuwa się jedno pytanie - ile to kosztuje? To zależy od operatora. Orange pobiera 25 groszy za 50 kB pobranych danych. Gdy z internetu korzysta się często, warto wykupić pakiet 5 MB za 5 zł. 5 MB w zupełności wystarczy do synchronizacji kalendarza i przeglądania kilku stron od czasu do czasu.