Skip to content

Instantly share code, notes, and snippets.

@stevecohenfr
Last active January 26, 2024 10:20
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save stevecohenfr/8d3908da4ed39169992e407261f4c0e6 to your computer and use it in GitHub Desktop.
Save stevecohenfr/8d3908da4ed39169992e407261f4c0e6 to your computer and use it in GitHub Desktop.
Read long SMS with python-gsmmodem (and send SMS with same running script)

Read long SMS with python-gsmmodem (and send SMS with same running script)

I spend a lot of time to replace gammu with python-gsmmodem for my Huawei E3531.

The python exemple is just an exemple, it's incomplete. It does not read sms in the memory (if you receive a sms before starting the script). And it does not concat multiple parts sms (it will print unordered parts).
Also, as your live read sms script is running, you cannot send sms with another script because the dongle is busy.

Here is my own script to read all kind of SMS and send in same time.

Install python-gsmmodem-new

Don't use python-gsmmodem that is deprecated but python-gsmmodem-new

Install dependencies

Install Pyro4:

pip  install  Pyro4

Install threaded:

pip install threaded

Start scripts

Listen for new SMS

$> python2.7 python-gsmmodem-advanced-read.py
Initializing modem...
Waiting for new SMS message...
Object <__main__.RemoteSMSHandler object at 0x764e9910>:
uri = PYRO:RemoteSMSHandler@127.0.0.1:9091
Pyro daemon running.

Keep this process running in background, for exemple with screen

Send SMS:

$> python2.7 python-gsmmodem-advanced-send.py --to=<receipient_number> --message=<your_message>
#!/usr/bin/env python
from __future__ import print_function
from datetime import datetime
from gsmmodem.modem import GsmModem, Sms
from gsmmodem.pdu import Concatenation
import logging
import Pyro4.core
import threading
PORT = '/dev/ttyUSB0'
BAUDRATE = 115200
PIN = None # SIM card PIN (if any)
concat_sms = {}
@Pyro4.expose
class RemoteSMSHandler(object):
def __init__(self, m):
self.modem = m
def sendSMS(self, to, message):
try:
self.modem.sendSms(to, message)
return "Message sent to {0}.\n".format(to)
except Exception, e:
return "Failed to send SMS: " + str(e)
def handleSms(sms):
concat = None
message = None
for i in sms.udh:
if isinstance(i, Concatenation):
concat = i
break
if concat:
if concat_sms.has_key(concat.reference) == False:
concat_sms[concat.reference] = {} #numpy.empty(concat.parts, dtype=string)
concat_sms[concat.reference][concat.number] = sms.text
print(u'== Partial message received ==\n[{0}/{1}] reference{2}\n'.format(len(concat_sms[concat.reference]), concat.parts, concat.reference))
if len(concat_sms[concat.reference]) == concat.parts:
sortedParts = sorted(concat_sms[concat.reference].iteritems())
message = "".join([x[1] for x in sortedParts])
del concat_sms[concat.reference]
else:
message = sms.text
if message:
print(u'== SMS message received ==\nFrom: {0}\nTime: {1}\nMessage:\n{2}\n'.format(sms.number, sms.time, message))
date = datetime.today().strftime('%Y%m%d%H%M%S%f')
# Uncomment to save the SMS in a file
#with open('/path/to/messages/' + date + '.txt', 'w') as the_file:
# the_file.write('{0}:{1}'.format(sms.number, sms.text))
def checkStoredSms(modem):
# print('Processing stored SMS...')
modem.processStoredSms(False)
threading.Timer(10.0, checkStoredSms, [modem]).start()
def main():
print('Initializing modem...')
# Uncomment the following line to see what the modem is doing:
#logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms)
modem.smsTextMode = False
modem.connect(PIN)
threading.Timer(10.0, checkStoredSms, [modem]).start()
print('Waiting for new SMS message...')
myRemoteSMSHandler = RemoteSMSHandler(modem)
daemon = Pyro4.Daemon.serveSimple({
myRemoteSMSHandler: 'RemoteSMSHandler',
}, host="127.0.0.1", port=9091, ns=False, verbose=False)
daemon.requestLoop()
if __name__ == '__main__':
main()
#!/usr/bin/env python
import Pyro4
import sys, getopt
myRemoteSMSHandler = None
def sendSMS(to, message):
print(myRemoteSMSHandler.sendSMS(to, message))
def main(argv):
global myRemoteSMSHandler
myRemoteSMSHandler = Pyro4.Proxy("PYRO:RemoteSMSHandler@127.0.0.1:9091")
messageReceipt = ''
messageText = ''
try:
opts, args = getopt.getopt(argv,"ht:m:",["to=","message="])
except getopt.GetoptError:
print 'sendsms.py --to=<receipient_number> --message=<your_message>'
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
print 'sendsms.py --to=<receipient_number> --message=<your_message>'
sys.exit()
elif opt in ("-t", "--to"):
messageReceipt = arg.strip()
elif opt in ("-m", "--message"):
messageText = arg.decode("string_escape")
sendSMS(messageReceipt, messageText)
if __name__ == "__main__":
main(sys.argv[1:])
@BernardOOO
Copy link

Hi,
thanks for your scripts.
I have an issue with the send script :
Here is the message :

pi@alarme:~ $ python2.7 python-gsmmodem-advanced-send.py --to=06XXXXXXX --message=message3
Traceback (most recent call last):
File "python-gsmmodem-advanced-send.py", line 33, in
main(sys.argv[1:])
File "python-gsmmodem-advanced-send.py", line 30, in main
sendSMS(messageReceipt, messageText)
File "python-gsmmodem-advanced-send.py", line 9, in sendSMS
print(myRemoteSMSHandler.sendSMS(to, message))
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/core.py", line 185, in call
return self.__send(self.__name, args, kwargs)
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/core.py", line 467, in _pyroInvoke
data = serializer.deserializeData(msg.data, compressed=msg.flags & message.FLAGS_COMPRESSED)
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/util.py", line 171, in deserializeData
return self.loads(data)
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/util.py", line 614, in loads
return self.recreate_classes(serpent.loads(data))
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/util.py", line 416, in recreate_classes
return self.dict_to_class(literal)
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/util.py", line 633, in dict_to_class
return super(SerpentSerializer, cls).dict_to_class(data)
File "/home/pi/.local/lib/python2.7/site-packages/Pyro4/util.py", line 395, in dict_to_class
raise errors.SerializeError("unsupported serialized class: " + classname)
Pyro4.errors.SerializeError: unsupported serialized class: gsmmodem.exceptions.CommandError
pi@alarme:~ $

Can you help me please?
Thanks,
Bernard.

@stevecohenfr
Copy link
Author

stevecohenfr commented Nov 11, 2019

@BernardOOO can you please check your Pyro4 version ?

$> sudo pip freeze | grep Pyro4
Pyro4==4.76

If you haven't this Pyro version please try to replace your version by this one :

pip uninstall Pyro4
pip install --upgrade Pyro4==4.76

Edit

It seems that the modem returns an error in response to an AT command. I updated python-gsmmodem-advanced-read.py to catch the exception and display it to the send command. Please try again and you will see what's wrong.

Steve

@BernardOOO
Copy link

Hi Steve,
thank you to consider my problem.

1 - Pyro4 installed version is 4.77
2 - Successfully installed version 4.76
And ... same problem.

3 - installed updated version of python-gsmmodem-advanced-read.py :
(after a reboot to kill any Pyro4 instance)
pi@alarme:~ $ python2.7 python-gsmmodem-advanced-read.py &
[1] 654
pi@alarme:~ $ Initializing modem...
Waiting for new SMS message...

Note : messages are NOT received ! (With prior version, messages were received normally)

pi@alarme:~ $ python2.7 python-gsmmodem-advanced-send.py --to=06XXXXXX --message=message3
Failed to send SMS: 0021000AA16058840938000008EDF27C1E3E9767

Does it says anything to you ?

Bernard.

@jr-k
Copy link

jr-k commented Feb 28, 2020

Thanks mate ! These gists help me a lot.

@CERT-o
Copy link

CERT-o commented Sep 1, 2020

Hi Steve,

Thanks for this script! I'm stuck trying to use gammu on a E3531 but I get all sort of random error messages.. So I ended up here :)

I'm trying to run your script in a raspberry pi 4 but I'm getting the following error:

pi@raspberrypi:~ $ python2.7 python-gsmmodem-advanced-read.py
Initializing modem...
INFO: Connecting to modem on port /dev/ttyUSB0 at 115200bps
DEBUG: write: ATZ
DEBUG: response: ['OK']
DEBUG: write: ATE0
DEBUG: response: ['OK']
DEBUG: write: AT+CFUN?
DEBUG: response: ['+CFUN: 1', 'OK']
DEBUG: write: AT+CMEE=1
DEBUG: response: ['OK']
DEBUG: write: AT+CPIN?
DEBUG: response: ['+CPIN: READY', 'OK']
DEBUG: write: AT+CLAC
Traceback (most recent call last):
File "python-gsmmodem-advanced-read.py", line 81, in
main()
File "python-gsmmodem-advanced-read.py", line 67, in main
modem.connect(PIN)
File "/usr/local/lib/python2.7/dist-packages/gsmmodem/modem.py", line 201, in connect
commands = self.supportedCommands
File "/usr/local/lib/python2.7/dist-packages/gsmmodem/modem.py", line 490, in supportedCommands
response = self.write('AT+CLAC')
File "/usr/local/lib/python2.7/dist-packages/gsmmodem/modem.py", line 398, in write
responseLines = SerialComms.write(self, data + writeTerm, waitForResponse=waitForResponse, timeout=timeout, expectedResponseTermSeq=expectedResponseTermSeq)
File "/usr/local/lib/python2.7/dist-packages/gsmmodem/serial_comms.py", line 135, in write
raise TimeoutException()
gsmmodem.exceptions.TimeoutException

On lsusb I get:
Bus 001 Device 022: ID 12d1:1001 Huawei Technologies Co., Ltd. E161/E169/E620/E800 HSDPA Modem

And gammu identify:
Device : /dev/ttyUSB0
Manufacturer : Huawei
Model : E3531 (E3531)

Anything else basic I might be missing ? Thanks!

@stevecohenfr
Copy link
Author

stevecohenfr commented Sep 1, 2020

Anything else basic I might be missing ? Thanks!

Hi @CERT-o, it seems that your dongle did not respond. Are you sure your sim is working well ? Try using it in your phone first and double check that you don't have a sim pin.
Moreover, are you using this version of python-gmsmodem ?

EDIT: please also check that gammu/gammu-smsd is not running. Dongles doesn't handle concurrent connexion.

Steve

@CERT-o
Copy link

CERT-o commented Sep 1, 2020

Hi Steve,

SIM is new and pin is default to 0000. At the end the python-gmsmodem was missing..joys of playing with pip and pip3. After rebooting and changing ports it now works just fine! Thanks again :)

@Sirvaude
Copy link

I can't see where to set the /dev/ttyUSB modem in the send sms code. Can you please elaborate this a bit more?

@stevecohenfr
Copy link
Author

/dev/ttyUSB is set in python-gsmmodem-advanced-read.py

Send script can only be use if Read script is running. Read script is the main script that communicate with your dongle. And send script communicate with read script to tell it to send sms. You know what I mean ? 🤔

@Sirvaude
Copy link

@stevecohenfr thanks you're right, I didn't read that script as I was just looking how to send a sms.

Btw, do you know all the AT commands involved in the process of getting and sending sms?

@stevecohenfr
Copy link
Author

@Sirvaude I don't remember AT commands used but you can search in gsmmodem library in this method : https://github.com/babca/python-gsmmodem/blob/ea7db39ade00260ec8fcb045fb8d0d2e683afbd7/gsmmodem/modem.py#L882

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment