CREATE YOUR OWN SMS GATEWAY

here i am gonna show you how to setup a simple sms gateway from a 3G USB dongle using python. the work-flow here is very simple. but before that let’s go through with some basics of 3G USB dongle.

in our gateway once a valid request from the internet is received to our gateway, it should communicate with the dongle and send the message included in the request to the relevant number in the request. so the most important part in this would be communicating with the dongle when the gateway receives some request.

basically your 3G dongle consists with a 3G modem and USB to serial converter. 3G modem is something like below image. to communicate with the modem, it needs a serial (RS-232) connection and this is where USB to serial converter comes to play.
as all modern laptops are consists of USBs this converter is also integrated inside the dongle so we can easily plug it and communicate. so the catch from here is that we can use RS-232 / serial to communicate with our dongle.

GSM / 3G modem module. a tiny compact module is used in a dongle
GSM / 3G modem module. a tiny compact module is used in a dongle

first let’s try to communicate with our dongle with the terminal and if it succeed we can automate that with python to use in our SMS gateway.

GSM / 3G module communication flow.
GSM / 3G module communication flow. source: http://www.engineersgarage.com/articles/gsm-gprs-modules

testing on terminal

first plug the dongle (assuming that you have inserted a sim card with credit in it 😛 ) and find out the port it opened. open terminal and issue dmesg | grep tty command to find out connected USB devices.
you will obtain an output like below.

[   14.124879] usb 1-1.4: GSM modem (1-port) converter now attached to ttyUSB0
[   14.126676] usb 1-1.4: GSM modem (1-port) converter now attached to ttyUSB1
[   14.127795] usb 1-1.4: GSM modem (1-port) converter now attached to ttyUSB2

now, let’s try to communicate with the dongle with the serial connection (RS 232). here we have to use AT commands to communicate. you can find the complete list of AT command set GSM/ 3G modems support from here.

we will be using picocom terminal program to communicate with the dongle via serial. install it as below.

sudo apt-get install picocom

now open the serial port. make sure the substitute relevant port of the dongle.

picocom /dev/ttyUSB0 -b 115200 -l

picocom v1.7

port is        : /dev/gsmmodem
flowcontrol    : none
baudrate is    : 115200
parity is      : none
databits are   : 8
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : no
nolock is      : yes
send_cmd is    : sz -vv
receive_cmd is : rz -vv
imap is        : 
omap is        : 
emap is        : crcrlf,delbs,

Terminal ready

try issuing AT command first. you should get an output like following if everything so far alright. 🙂 issue following AT commands as well to make enable text mode for SMS.

AT
OK

AT+CMGF=1
OK

now let’s try to send a message. enter message in following format.
AT+CMGS="phonenumber"<CR>the message to send<ctrl+z>
after the number and the end of double quote hit enter, then type the message. hit ctrl + z.

it’ll give u a OK response and in a while you should receive a text message to your specified number. if all is good, its time to write our gateway piece. 😀

building the gateway

i’ll be using flask for the REST API and a python module called python-messaging for encoding text messages to PDU format.

first install those packages by:

pip install flask
pip install git+https://github.com/pmarti/python-messaging.git

now, lets get into coding. open a new file, say gateway.py. lets first write a function to open the serial port and issue relevant AT command to send the message.

from messaging.sms import SmsSubmit
import serial


def send_text(number, text, path='/dev/ttyUSB0'):
    sms = SmsSubmit(number, text)
    pdu = sms.to_pdu()[0]

    # print len(sms.to_pdu())

    # open the modem port (assumes Linux)
    ser = serial.Serial(path, timeout=1)
    # write the PDU length and wait 1 second till the
    # prompt appears (a more robust implementation
    # would wait till the prompt appeared)
    ser.write('AT+CMGS=%d\r' % pdu.length)
    print ser.readlines()
    # write the PDU and send a ctrl+z escape
    ser.write('%s\x1a' % pdu.pdu)
    ser.close()

now, let’s attach this as a response to a valid POST request. we’ll use HTTP basic auth for authentication.
1. first let’s write a simple function to check user name and password.
2. then basic auth handler to be used in POST request
3. finally the POST request

from flask import Flask, jsonify, request
from functools import wraps
app = Flask(__name__)

def check_auth(username, password):
    """check username / pass"""
    return username == 'user' and password == 'mypassword'


def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return jsonify({'message': 'not logged in'}), 404
        return f(*args, **kwargs)
    return decorated


@app.route("/")
def hello():
    return "python sms gateway :)"

# POST request handler
@app.route('/send', methods=['POST'])
@requires_auth
def create_task():
    if not request.json or not 'number' in request.json:
        return jsonify({'message': 'no number provided'}), 400

    send_text(request.json['number'], request.json['text'])
    return jsonify({'message': 'message queued'}), 201

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=4000)

so the full code for the gateway will look like below.

gateway.py

from messaging.sms import SmsSubmit
import serial
from flask import Flask, jsonify, request
from functools import wraps
app = Flask(__name__)


def check_auth(username, password):
    """check username / pass"""
    return username == 'user' and password == 'mypassword'


def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return jsonify({'message': 'not logged in'}), 404
        return f(*args, **kwargs)
    return decorated


def send_text(number, text, path='/dev/ttyUSB0'):
    sms = SmsSubmit(number, text)
    pdu = sms.to_pdu()[0]

    # print len(sms.to_pdu())

    # open the modem port (assumes Linux)
    ser = serial.Serial(path, timeout=1)
    # write the PDU length and wait 1 second till the
    # prompt appears (a more robust implementation
    # would wait till the prompt appeared)
    ser.write('AT+CMGS=%d\r' % pdu.length)
    print ser.readlines()
    # write the PDU and send a ctrl+z escape
    ser.write('%s\x1a' % pdu.pdu)
    ser.close()




@app.route("/")
def hello():
    return "python sms gateway :)"


@app.route('/send', methods=['POST'])
@requires_auth
def create_task():
    if not request.json or not 'number' in request.json:
        return jsonify({'message': 'no number provided'}), 400

    send_text(request.json['number'], request.json['text'])
    return jsonify({'message': 'message queued'}), 201

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=4000)

now run the gateway by issuing python gateway.py. our gateway server now would be running on http://localhost:4000 in the host machine. next let’s use postman to send a test request and ensure that our gateway is working. download postman from chrome web store if you don’t have it installed.

format the request as below. 😛

postman_1

postman_3

if all is good, you should now receive a text from the dongle.

you can find the complete source code of the project from https://github.com/wathmal/sms-gateway.

references:
* https://myraspberryandme.wordpress.com/2013/09/13/short-message-texting-sms-with-huawei-e220/
* https://github.com/pmarti/python-messaging/blob/master/doc/tutorial/sms.rst