Pull to refresh

sms2twitter гейт за 5 минут

Reading time 6 min
Views 1.7K
imageЦелью статьи является демонстрация возможностей Python for s60 для работы с смс сообщениями и базами данных. Чтобы было интересней, разберем на реальном примере, создадим приложение, которое будет читать новые сообщения смартфона, парсить их, сохранять в свою базу данных номера телефонов с логинами и паролями, и постить твиты, пришедшие с этих номеров.

Для чего это еще может пригодиться? В наше время смс сервисы используются достаточно широко. Способов их реализации достаточно много. У меня недавно возникла необходимость реализовать сервис, при котором клиенты могли бы посылать смс сообщением номер заказа и в ответ приходил бы его статус. Задача решилась так: за 500 руб., на барахолке был куплен старенький Nokia 7610 в разваливающемся состоянии, у которого не работала половина кнопок, были проблемы со звуком и т. д. Туда была вставлена сим карта от местного оператора с безлимитным смс пакетом. Теперь этот аппарат будет играть роль сервера, который будет работать в режиме 24/7, с бесперебойным источником питания (аккамулятор), и не будет знать проблем с охлаждением :)



Работа с смс сообщениями


Тут все просто. Есть модуль inbox, которые позволяет нам работать с сообщениями в нашем телефоне. У этого модуля одноименный класс Inbox, которые позволяет прочесть сообщение, отправителя и время. У каждого сообщения есть свой ID. Список ID всех сообщений можно получить функцией sms_messages(). Но нам более интересна функция bind, которой мы указываем функцию, которая будет вызываться сразу же, как только нам поступит новое сообщение.

Выглядеть это будет вот так:

  1. #coding:utf-8
  2. import e32
  3. from appuifw import app
  4. import inbox
  5.  
  6. class Main:
  7.  
  8.     def incoming_callback(self,id):    
  9.         print 'incoming message'
  10.         # делаем небольшую паузу, чтоб не было конфликтов 
  11.         # с приложением "Сообщения"
  12.         e32.ao_sleep(1)
  13.         # создаем новый экземпляр класса Inbox, так как в старом
  14.         # не будут видны вновь поступившие сообщения
  15.         messages=inbox.Inbox()
  16.         # получаем содержание сообщения и адрес, откуда оно пришло
  17.         print messages.content(id)
  18.         print messages.address(id)
  19.         # и удаляем его, чтоб оно нам не мешалось
  20.         messages.delete(id)    
  21.  
  22.     def __init__(self):
  23.         # создаем экземпляр класса inbox и биндим к входящим функцию
  24.         self.inb=inbox.Inbox()
  25.         self.inb.bind(self.incoming_callback)
  26.         print 'Start'
  27.  
  28. lock=e32.Ao_lock()
  29. app.exit_key_handler=lock.signal
  30. a=Main()
  31. lock.wait()


Хотелось бы упомянуть об особенности адреса в сообщении. Если нам пришло сообщение, номер отправителя которого есть в записной книжке телефона, то в address нам вернет имя, а не номер. Если же абонента и записной книжке нет, то мы получим строку с номером.

Работа с базой данных


Через python есть возможность работать с нативной базой данных symbian — dbms, которая представляет собой реляционную базу данных, и поддерживает sql синтаксис. Мне доводилось работать 600-800 тысячами записей на относительно старом смартфоне nokia 3230, который достатоно неплохо справлялся с таким объемом данных.

Есть 2 модуля для работы с базами данных e32db, который работает непосредственно с базой данных и e32dbm, который является надстройкой над e32db и реализует интерфейс базы данных ключ-значение. Не смотря на то, что в данном случае мы будем использовать e32dbm, я хотел бы показать, как работать с e32db. Те, кто пишет на питоне, наверняка привыкли к DB API 2, поэтому принципы работы с этой базой покажутся немного странными.

У e32db есть 2 класса. Один для записи в базу, другой для чтения.
Создание базы данных, создание таблиц и их наполнение выглядит так:
  1. import e32db
  2. db_path=u'e:\\data\\python\\test.db'
  3. db=e32db.Dbms()
  4. db.create(db_path)
  5. db.open(db_path)
  6. db.execute(u'CREATE TABLE users (number CHAR(12), login LONG VARCHAR, password LONG VARCHAR)')
  7. db.execute(u"""INSERT INTO users VALUES('+79xxxxxxxxx','kAIST','password')""")

Не забываете, что путь к базе и запросы должны быть в юникоде.
С чтение из базы данных немного посложнее.
  1. db_view=e32db.Db_view()
  2. # делаем запрос, указывая уже открытую базу данных
  3. db_view.prepare(db,u'SELECT * from users')
  4. # проходимся по всем строкам
  5. for x in xrange(db_view.count_line()):
  6.     # подготавлием новую строку к выдаче
  7.     db_view.get_line()
  8.     # и смотрим, что у нас в колонках
  9.     # странно, но нумерация начиниается с 1 а не с 0
  10.     print db_view.col(1),db_view.col(2)
  11.     # переходим на следующую строку
  12.     db_view.next_line()


Для работы приложения, нам хватит e32dbm, работать с которой проще простого:
  1. import e32dbm
  2. db=e32dbm.open(u'e:\\data\\python\\test','c')
  3. db['first']='hello'
  4. db['second']='second key'
  5. db.sync()
  6. db.close()


Перейдем непосредственно к нашей задаче


Возьмем за основу наш код, который получает смс сообщения. Добавим в начало следующие строки:
  1. import e32dbm
  2. db=e32dbm.open(u'e:\\mydb','c')


Осталось написать функцию, которая будет парсить сообщения. Для того, чтобы абонент мог работать с этим гейтом, его номер нужно ассоциировать с аккаунтом на твиттере. Давайте не будем перебирать все возможные варианты авторизации и спорить о безопасности, а просто введем две команды: add login password и delete. Первая команда, посланная на телефон будет добавлять в базу данных логин и пароль, ассоциированные с номером телефона, а вторая удалять. Соответственно, после такой авторизации, пользователь сможет просто писать на номер гейта смс, которые будут уходить на твиттер.
  1.     def parse(self,content,address):
  2.         if content.startswith('add'):
  3.             print 'Add:',address
  4.             db[address]=repr(content.split()[1:3])
  5.             db.sync()
  6.         elif content.startswith('delete'):
  7.             if address in db.keys():
  8.                 print 'Delete:',adress
  9.                 del db[address]
  10.                 db.sync()
  11.         else:
  12.             if address in db.keys():
  13.                 print 'Send:',address
  14.                 self.send_twit(db[address],content)

и в функцию incoming_callback добавляем строчку:
self.parse(messages.content(id),str(hash(messages.address(id))))

И осталось реализовать добавление твита, как мы это делали в этом топике.
    def send_twit(self,tw,content):
        login,password=eval(tw)
        api = tweepy.API.new('basic', login, password)
        api.update_status(content)

Теперь наш гейт готов. По желанию, его можно упаковать в sis и подпилить напильником в плане обработки ошибок.
Исходики, берем здесь, а готовый sis здесь
Свежих вам идей!
Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+51
Comments 29
Comments Comments 29

Articles