I'm trying to send SMS from my RaspberryPi using my own script in python. I'm using serial port on GPIO on the RPi to communicate with GSM modem. I have selected TEXT MODE sms format, listed smses, etc and it all works fine until it comes to sending a sms. When I want to send it I get error like in the tittle.
To quit sending a message I press esc button, press enter (to send it via serial) and it works great (modem sends back 'OK')
I know that to send a message, after the message content I have to send ctrl-z. Ofc in linux when i press ctrl-z i stop the program so it's impossible to press those keys and then enter. Thats why i made a function to send sms where i put ctrl-z char/sign.
When i run the program modem responds with an error like in the tittle(+CME ERROR: invalid paremeter or if you'd like the error code: +CME ERROR: 3518) I know this may seem stupid but I've been looking for an answer for two days and I've tried chr(26).encode(), "\x1a", "\x1A" (don't even know if there's a difference), I've tried to send it with a message content, separatly but nothing works
I may do something wrong but I have no idea what. So I post some code and datasheet screen how to send a message.
Sending a sms:
def sendSMS(self, phoneNumber=111111111, smsContent=""):
# if phoneNumber==0:
if phoneNumber!=111111111:
print("Type phone number in: (without prefix +48): ", end="")
phoneNumber = input()
try:
phoneNumber = int(phoneNumber)
except Exception:
print("Type in an integer")
time.sleep(1)
self.sendSMS()
print("Type text message content (press ENTER to send): ")
smsContent = str(input())
char_CtrlZ = "\x1a"
quote = "\""
command = "AT+CMGS=" + quote + str(phoneNumber) + quote + "," + quote + "129" + quote
message = smsContent + char_CtrlZ
self.serialConnection.send(command)
time.sleep(1)
self.serialConnection.receive()
time.sleep(1)
if self.checkModemResponse()==True: #here I send empty string (few times, if needed) until modem responses with '>'
print("No '>' in modem response")
print("Message did not send")
else:
self.serialConnection.send(message, True, False)
time.sleep(2)
self.serialConnection.receive(True, True, True)
time.sleep(1)
if self.serialConnection.responseState=="COMPLETE_OK":
print("Your message has been sent!")
def checkModemResponse(self, attempt=3):
#I have 5 states of response: UNKNOWN; COMPLETE_OK - modem responses with OK; COMPLETE_ERROR - modem responses with ERROR; UNCOMPLETE - modem responses correctly but without ERROR or OK; EMPTY modem responds correctly but with empty string
isUncomplete = True
if self.serialConnection.responseState!="UNCOMPLETE":
isUncomplete = False
attempt -= 1
if attempt > 0:
print("Trying again..")
someString = "attempt: " + str(attempt)
self.serialConnection.send(someString)
time.sleep(1)
self.serialConnection.receive(True, True, True)
time.sleep(1)
if self.serialConnection.responseState!="UNCOMPLETE":
self.checkModemResponse(attempt)
return isUncomplete
And sending a command over serial:
def send(self, messageToSend, printWhatIsSent=True, addCR=True):
if addCR==False:
command = messageToSend
else:
command = messageToSend + "\r"
if self.serialState==self.SERIAL_STATE[IDLE] and self.serialConnection.isOpen():
self.responseState = self.RESPONSE_STATE[UNKNOWN]
self.serialState = self.SERIAL_STATE[SENDING]
commandToSendInBytes = self.str2byte(command)
self.serialConnection.write(commandToSendInBytes)
self.serialState = self.SERIAL_STATE[IDLE]
if printWhatIsSent==True:
print(">>>>> command sent: " + messageToSend)
else:
print("!!!ERROR: COMMAND DID NOT SEND!!!")
self.serialConnection.flushOutput()
How to send an SMS: +CMGS datesheet screenshot
Related
I am currently working on a program in Python that works as a client, and needs to connect remotely to a server using the TCP/IP protocol. After the server receives the client's username, the client can send messages to other clients by typing "#<username> <message>", and this input will be further processed and the message that will be sent to the server will be constructed as "SEND <username> <message>", and this will be actually recognized by the server. Then the server will send back an acknowledgement to the sending client, and the actual message to the destination client.
My approach is to use a main function named chat_run(), used for input and constructing the message that will be sent to the server, and in parallel to run a function named OutputRecvMsg() in a different thread that will receive messages from the server and output them in the console.
The problem is, I want the beginning of all the input lines to start with username >, and the messages received from the server to be output immediately on a new line, and the client to wait for a new input.
My current implementation problem seems to be in receiving messages (the OutputRecvMsg() function). After it outputs a message to the console, I need to press Enter to ask for input, because it remains stuck.
For me, there are two questions regarding the current problem, maybe two threads try to access the same resource (console), maybe I made a mistake regarding the construction of the received message (because I know that sock.recv(4096) is blocking and I tried to avoid a blocking state).
import socket
import time
import re
import threading as th
SERVER_REPLY_1 = 'HELLO'
SERVER_REPLY_2 = 'IN-USE'
AT_SYMBOL = '#'
host_port = ('remote_server_add', 5378)
def build_loggin_msg(msg):
return 'HELLO-FROM ' + msg + ' \n'
def chat_run(sock, currentUser):
while True:
rawInput = input(currentUser + '> ')
if rawInput == '!who':
sock.sendall('WHO\n'.encode())
elif rawInput == '!quit':
sock.close()
break
else:
splittedMsg = re.split(r'\s', rawInput, maxsplit = 1)
if len(splittedMsg) > 1 and splittedMsg[0].startswith(AT_SYMBOL):
userNameToSend = splittedMsg[0][1:]
message = 'SEND ' + userNameToSend + ' ' + splittedMsg[1] + ' \n'
sock.sendall(message.encode())
def OutputRecvMsg(sock, currentUser):
OutMsg =''
chunk = ''
while True:
try:
chunk = sock.recv(4096).decode()
if not chunk:
pass
else:
OutMsg += chunk
except BlockingIOError as e:
if OutMsg:
print(OutMsg)
OutMsg = ''
if __name__ == '__main__':
loggedIn = False
currentUser = None
_data = ''
while not loggedIn:
currentUser = input('Add a username please: ')
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(host_port)
sock.sendall(build_loggin_msg(currentUser).encode())
data = sock.recv(4096).decode()
print(data)
if data.startswith(SERVER_REPLY_1):
loggedIn = True
else:
print('Close connection for retry another username')
sock.close()
time.sleep(1)
sock.setblocking(0)
th.Thread(target=OutputRecvMsg, args=(sock, currentUser)).start()
chat_run(sock, currentUser)
As an example:
Add a username please: Nickname
HELLO Nickname
Nickname> #Nickname hello man -> send to me
Nickname> DELIVERY Nickname hello man
SEND-OK -> here I have to press enter to get the next lines
Nickname>
I'm looking to build a chat room in python at the moment and am struggling with direct messages as I'm using client.recv(2048) function in both my thread listening for messages from the server and trying to use client.recv() in my main function to receive a list of active users on the server. It seems the program will work sometimes and others will shift to the clientreceive function.
Thread started
# Starts thread for client receive
receive_thread = threading.Thread(target=client_receive)
receive_thread.start()
receive block
def client_receive():
while True:
try:
message = client.recv(2048).decode()
print(message)
except:
client.close()
break
main method (DM)
if msg_type == "DM":
# Sends C DM message to server
dm_msg = "C DM"
client.send(dm_msg.encode())
# Receives list of online users from server in client_receive
users = client.recv(2048).decode()
print(users)
# Client inputs username and message to server
target = input("Select user: ")
chat = input("> ")
chat_msg = "D " + target + "|||||" + chat
I attempted using locks in my main method, which did not seem to work. I expected my method to stay with my socket when I used lock.acquire(), however it still broke to the clientreceive function
Thanks
In our SMS server we have an old GSM modem(Siemens iRZ ES75iT) connected by COM port.
We have a python script which allows to send SMS messages.
Here is the code of sms sender function:
def sendsms(to, message):
message = message.replace('#', '\0')
if (len(message) > 140 ):
message = message[0:140]
print "Connecting phone"
ser = serial.Serial('/dev/ttyS0', 115200, timeout=12)
time.sleep(1)
ser.write('AT\r')
time.sleep(1)
print "AT"
ser.write('AT+CMGD="ALL"\r')
time.sleep(2)
print "AT+CMGDA=DEL ALL"
ser.write('AT+CMGF=1\r')
time.sleep(1)
print "AT+CMGF=1, text mode"
ser.write('''AT+CMGS="''' + to + '''"\r''')
time.sleep(2)
ser.write(message + "\r")
time.sleep(3)
ser.write(chr(26))
time.sleep(1)
print message
print "disconnecting"
ser.flush()
ser.close()
The script usually working as expected but sometimes we get SMS containing "AT" string in the text, like
"**AT** <text we expect to see>"
or
"<text we expect to see> **AT**"
The question is why we are getting such text in the message and how to avoid it? Thanks in advance.
This is an issue related to at command echo, every time you send an AT command it is echoed on serial. We have python scripts for sending sms.
what we normally do is disable the echo before sending any AT command.
send this command
ser.write('ATE0\r')
This command will turn off the echo
before sending
ser.write('AT')
Hope this helps
[EDIT:]
I'm currently trying to make a small tcp chat application. Sending and receiving messages already works fine... But the problem is:
When i start typing a message while i receive one... it appears after the text I'm writing
Screenshot: http://s7.directupload.net/images/140816/6svxo5ui.png
[User sent > "hello", then I started writing "i am writing..." then user wrote " i sent a..." before i sent my message... so it has been placed after my input...
I want the incoming message always to be before my input !
this is my current code:
Client.py
con = connect.User()
server = raw_input("Type in the server adress \n[leave blank to use xyr.no-ip.info]\n>:")
nick =""
while nick == "":
nick = raw_input("Type in your nickname\n>:")
con.connect(server, nick)
def sender():
print("Sender started")
while 1:
msg = raw_input()
if msg == "q":
break
con.send(msg)
con.disconnect()
def receiver(server):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server == "":
server="xyr.no-ip.info"
sock.connect((server, 8000))
sock.send("%pyreceiver\n")
print("Receiver started")
while 1:
msg_in = sock.recv(1024)
if not str(msg_in).startswith("[py]" + nick):
if str(msg_in).startswith("/ua"):
print(str(msg_in)[3:])
elif str(msg_in).startswith("/u "):
print(str(msg_in)[2:])
else:
print(str(msg_in[:-1]))
#
if nick == "":
nick = "guest"
print("Name changed to ""guest""")
time.sleep(.5)
thread.start_new_thread(receiver, (server, ))
time.sleep(.5)
thread.start_new_thread(sender())
Connect.py
import socket
import time
class User():
nickel =""
def connect(self, server="xyr.no-ip.info", nick="guest"):
nickel = nick
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if server == "":
server="xyr.no-ip.info"
print("server changed to xyr.no-ip.info")
time.sleep(.5)
print("Connecting...")
self.sock.connect((server, 8000))
print("Connected")
time.sleep(.4)
self.sock.send("[py]" + nick + "\n")
self.sock.send(nick + " connected with a python client\n")
print("registered as " + nick)
time.sleep(.3)
def send(self, msg):
self.sock.send(msg + "\n")
def disconnect(self):
self.sock.close()
print("disconnected")
Your code writes everything to stdout. Whenever something arrives to either of your sender/receiver threads, it prints to stdout. The issue with that is, due to the fundamental nature of output streams, you cannot accomplish the following :
place incoming messages above the stuff currently being typed/echoed.
Things happen strictly in the order of occurrence. The moment something comes in, wherever the cursor is, the print statement dumps that data over there. You cannot modify that behaviour without using fancier / more powerful constructs.
In order to do what you want, I would use ncurses. You seem to be using python on Windows, so you're going to have to do some digging on how to get equivalent functionality. Check out this thread : Curses alternative for windows
I had a similar problem and I found that a simpler solution (for me) was to get input via readchar (https://github.com/magmax/python-readchar/tree/master/readchar).
Using readchar, I would buffer each keystroke (checking for key.BACKSPACE and CR - see code snippet below).
All output I would prepend with "/033[1A" (make the cursor move up), print the output line, and then a "/n"...
after each output line, I move the cursor to the beginning and re-print the self.input_buff
while the user is doing input, this handles console input, displaying what they are typing:
keypress = readkey()
if keypress == key.BACKSPACE:
self.input_buff = self.input_buff[:-1]
print("\033[0A%s " % self.input_buff)
continue
if keypress != key.CR:
self.input_buff = "%s%s" % (self.input_buff, keypress)
print("\033[0A%s" % self.input_buff)
continue
This kept the input line at the bottom and all terminal output above it.
I know it comes a year late and if you are a wiz with curses, maybe that is the way to go...
Python: socket.recv() doesn't receive push messages
Hello,
I'm coding a socket based IMAP client in Python3 which successfully establishes a connection to the server, succussfully transmits the IDLE command but then fails to receive incoming data from the server.
If you are wondering why I do not use libimap or sth., the answer is easy: I just want to implement an IDLE command-supporting python client which must be written without that library.
An extract:
import socket
def runIMAPPeek():
#socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(29 * 60)
#connection
s.connect((IMAP_SERVER , 443))
#login
data = b"a1 LOGIN " + USER + b" " + PASSWORD + b"\n"
s.sendall(data)
reply = read(s)
#Idle loop
#As in RFC 3501 connection will be reinitialized every 29 minutes
while True:
# Idle command
print("#Sending IDLE...")
data = b"a2 IDLE\n"
s.sendall(data)
reply = read(s)
if reply.startswith("+ idling"):
print(" #idling.")
else:
print(" #Unexpected answer: {}".format(reply))
#sys.exit()
# waiting for incoming mails ----------------------------------
try:
push_msg = read(s)
# got push message = new message arrived
getNewEnvelope(s, push_msg)
except socket.timeout:
# timeout
print(" #timeout. Reinitializing IDLE...")
#TODO: except (KeyboardInterrupt, SystemExit)
# Quit Idle
data = b"DONE\n"
write(s, data)
reply = read(s)
if reply.startswith(prefix_str + " OK"):
print(" #quit idling.")
else:
print(" #Unexpected answer: {}".format(reply))
#sys.exit()
def read(s):
"""Read socket data, print it, convert to string, replace new lines
and return it.
"""
print("#Receiving...", end=" ")
reply = s.recv(4096)
reply = str(reply)[2:-1] #convert and remove byte indicators
reply = reply.replace("\\r\\n", "\n")
print(reply)
return reply
The problem is marked with the "----". Although messages are received in the mailbox, python does not react but remains in the idling/receiving state. In fact, the print line above the s.recv() command isn't even printed.
I tried everything successfully with Telnet, so there is no server problem.
In addition to my comment above, you have never selected INBOX. You will not receive any push messages, because you haven't told it what folder you want. Technically, IDLE is not valid in the unselected state.
Constructs like this one:
if reply.startswith("+ idling"):
are completely non-compliant. The IDLE RFC specifies that the client shall expect a continuation request, not this particular string (which also happens to be a continuation request).