python-messaging: SMS encoder/decoder for the masses
python-messaging is a pure python SMS encoder decoder. Some of its features:
- 7bit/8bit/UCS2 encoding: Now you can text your Chinese friend
- Multipart SMS: Because sometimes 140 chars are not enough
- SMS status report: Be sure they read it
- Stuff you take for granted: Alphanumeric addresses, timezone awareness, good test coverage
- Used in production by several projects: Wader, BCM and MobileManager
As far as we know, is the most advanced SMS encoder/decoder written in pure Python (otherwise we would be using it ;) If you need a PDU encoder/decoder for your project, python-messaging should fit your needs.
API walkthrough
>>> from messaging import PDU
>>> p = PDU()
>>> p.encode_pdu('+342323312', 'hello')
[(18, '001100099143323213F20000AA05E8329BFD06')]
>>> p.encode_pdu('+342323312', 'hello', csca='+345343234')
[(18, '069143353432F41101099143323213F20000AA05E8329BFD06')]
>>> p.encode_pdu('+342323312', 'hello', csca='+345343234', request_status=True)
[(18, '069143353432F43102099143323213F20000AA05E8329BFD06')]The only class you need to deal with is PDU. It is able to encode and decode PDUs with two simple functions: encode_pdu and decode_pdu. encode_pdu receives a number and the text you want to send, plus a number of optional parameters where you can specify smsc, validity, reference number, whether you want a confirmation or not, etc. The function returns a list of tuples with the pdu length and the pdu as a string ready to be sent via the serial port. Why a list of tuples? Well, you might want to send a SMS with more than 140 chars. If so, every fragment of the SMS will be a tuple in the list.
python-messaging can not send the SMS, is just an encoder! This is what you need to do in order to send a SMS with pyserial and python-messaging:
import messaging
import serial
def send_text(number, text, path='/dev/ttyUSB0'):
# encode the SMS
p = messaging.PDU()
# notice how I get the first returned element, this does
# not deal with concatenated SMS.
pdu_length, pdu = p.encode_pdu(number, text)[0]
# 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)
ser.close()
send_text('+3223223', 'hey how are you?')Updated: The above snippet had an error, it was trying to send the SMS with GMCS instead of CMGS, thanks Jakob for spotting it.
It was not too hard was it? This code does not deal with PIN authentication by the way, so be sure your device is already authenticated, or auth is disabled. Oh by the way, sending a UCS2 encoded message is easy, just pass a unicode string and the PDU object will do the right thing.
Decoding a PDU is a no brainer:
>>> p.decode_pdu('07911326040000F0040B911346610089F60000208062917314080CC8F71D14969741F977FD07')
{'cnt': 0, 'seq': 0, 'text': u'How are you?', 'fmt': 0, 'pid': 0, 'csca': '+31624000000', 'number': '+31641600986', 'type': 0, 'date': '02/08/26 19:37:41', 'ref': 0}This PDU string was taken from redxanela's online decoder default text, you can compare python-messaging's output with redxanela. Check out the method signatures for what options accepts. I need to write a thorough documentation one of this days, this is an initial effort in that way.
Hope you liked this walkthrough and that python-messaging fits your project needs. I didn't want to bother you with the project's history, you can check it out in the README. Looking forward to any questions/contributions ;-)
blog comments powered by Disqus