Python3 RSPI3 Serial Object Programming - python

I'm using today for a project a GSM/GPRS RSPI module. My job is to send, with AT commands, files to a FTP server (it's working by a simple program in Python or with putty by sending all AT commands one by one).
Today, to simplify my code, i chose to translate the code in object.
Also, i create my class with all my methods like send SMS, connectGPRS, sendFTP... (these methods do not appear to simplify the code)
But when i'm launching my program, i don't receive my confirm's reply from the module.
When isReady() start, the program send serial command to test the module. But i don't have any reply. My serial port configuration seems like right (debug() return ttyAMA0), and i can control my module by using Putty. But when i'm doing a short circuit with Tx and Rx, i can't see the request from the program on Putty.
Then my program stop in line sys.exit(0) with ser.isReady() returning false.
So my question is : It is possible to use Serial port, like i used it, in object programming ? Or do i make a mistake in my code ?
Regards. (sry btw for my frenchglish)
import serial
print("Reset du module")
resetModem()
time.sleep(5)
ser = ConnexionModule(SERIAL_PORT, 9600, 5)
if not ser.isReady():
print("Failed reboot, maybe a another program connected on serial, or the device isn't lauched")
sys.exit(0)
#debug() is a print function
def debug(text):
if VERBOSE:
print("Debug:---", text)
# This class is in reality in a another file imported in main
class ConnexionModule():
def __init__(self,serial_port,baudrate,timeout):
self.ser = serial.Serial(serial_port, baudrate, timeout)
# Testing if the module is ready to be used
def isReady(self):
# Resetting to defaults
cmd = 'ATZ\r'
# When i send 'ATZ' the module return 'OK'
debug("Cmd: " + cmd)
self.serialwrite(cmd,2)
reply = self.ser.read(self.ser.inWaiting())
reply = reply.decode("utf-8")
time.sleep(8) # Waiting for a reply
debug("Reply: " + reply)
return ("OK" in reply)
def serialwrite(self,cmd,slp):
debug("Sending:")
debug(self.ser.port)
debug(cmd)
self.ser.write(cmd.encode())
time.sleep(slp)
This code working :
import serial
print("Reset du module")
resetModem()
ser = serial.Serial(SERIAL_PORT, baudrate = 9600, timeout = 5)
if not isReady(ser):
print("Fail reboot")
sys.exit(0)
def isReady(pserial):
# Resetting to defaults
cmd = 'ATZ\r'
debug("Cmd: " + cmd)
serialwrite(pserial,cmd,2)
reply = pserial.read(pserial.inWaiting())
reply = reply.decode("utf-8")
time.sleep(8)
debug("Reply: " + reply)
return ("OK" in reply)
def debug(text):
if VERBOSE:
print("Debug:---", text)
def resetModem():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(P_RESET, GPIO.OUT)
GPIO.output(P_RESET, GPIO.LOW)
time.sleep(0.5)
GPIO.output(P_RESET, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(P_RESET, GPIO.LOW)
time.sleep(3)

Related

Looking for help in making my socket messenger send instantaneously in Python

Im sure there are easier ways with particular python modules, but for an assignment I need to create a program that can act as a client/server. As of right now I have it working to the point of only being able to send a message if the reciever has responded. I need it to just send and appear on the respective client/server terminal when enter is pressed. Any help would be greatly appreciated!
These are pictures of what happens as of now
https://i.stack.imgur.com/T9CsJ.png
import sys
import socket
import getopt
def usage(script_name):
print('Usage: py' + script_name + '-l' +' <port number>' + '[<server>]')
def sockObj():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
return sock
def serversockConn(serversocket,port):
serversocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# bind the serversocket to address
serversocket.bind(('',int(port)))
# enable a server to accept connections
serversocket.listen(5)
# wait for a connection and accept it
sock,addr = serversocket.accept()
return sock
def connToServersock(sock,server, port):
# connect to a serversocket
if server:
sock.connect((server, int(port)))
else:
sock.connect(('localhost', int(port)))
return sock
if __name__ == '__main__':
## get the command line arguments
try:
options, non_option_args = getopt.getopt(sys.argv[1:],'l')
except getopt.GetoptError as err:
print(err)
sys.exit(2)
#check if '-l' is present in command line agrument
serverSide = False
for opt,arg in options:
if opt == "-l":
serverSide = True
# port number
port = non_option_args[0]
# server address
server = None
hostLen = len(non_option_args)
if hostLen == 2:
server = non_option_args[1]
# create a communicator object, and make a connection between server and client
# server
if serverSide:
serversocket = sockObj()
sock = serversockConn(serversocket,port)
# client
else:
sock = sockObj()
sock = connToServersock(sock,server,port)
while True:
## read a message from standard input
message = sys.stdin.readline().encode()
if len(message) != 0:
sock.send(message)
return_msg = sock.recv( 1024 )
if return_msg:
print("Message recieved: " + return_msg.decode())
else:
print("Other side shut down")
else:
try:
sock.shutdown(socket.SHUT_WR)
sock.close()
except:
pass
I think your issue is that there are two places in your event loop where you block:
message = sys.stdin.readline().encode()
Here, you block until the user has pressed return -- during this time, your program is unable to respond to any data received over the network, because it is blocked waiting for data from stdin.
... and:
return_msg = sock.recv( 1024 )
Here, you are waiting for data to be received from the network -- during this time, your program is unable to respond to any data received from stdin, because it is blocked waiting for data from the network.
The behavior you'd ideally like to have is for your program to wait for both stdin and network traffic simultaneously -- i.e. have it block until either the user has pressed return, or some network data has been received, whichever comes first.
The easiest way to achieve that behavior is to use select(); its purpose is to block until at least one of several file descriptors is ready to be acted on. (Note, however, that Windows does not support using select() on stdin, so if your program needs to run under Windows you will probably have to spawn a second thread instead).
To implement the event loop using select(), add import select to the top of your script, then replace your event loop with something like this instead:
while True:
## block here until either sock or sys.stdin has data ready for us
readable, writable, exceptional = select.select([sock, sys.stdin], [], [])
if sys.stdin in readable:
## read a message from standard input
message = sys.stdin.readline().encode()
if len(message) != 0:
sock.send(message)
if sock in readable:
## read a message from the network
try:
return_msg = sock.recv( 1024 )
if (return_msg):
print("Message received: " + return_msg.decode())
else:
print("Other side shut down")
break
except:
print("recv() threw an exception")
break

Multiline serial read in Python 3

I am playing around with bidirectional serial communication between my PC and a STM32 development board. I am using Python 3.7 with PySerial 3.4 to open the serial port and receive/transceive messages from/to the dev board. Everything is working as expected except when I try to read and print multiline messages. In this case I only get the first line of the message.
The program on the microcontroller is such, that I get a multiline help-message back, if I send 'H' via serial to the controller board.
The multiline message the dev board is sending back looks like this:
"HELP\r\nList of commands:\r\nH: Display list of commands\r\nS: Start the application"
So I am expecting to see the following printout:
HELP
List of commands:
H: Display list of commands
S: Start the application
But instead I only get:
HELP
If I connect to the port with PuTTY and send 'H' manually, I get the full message; so I know that it is not a problem of my microcontroller program.
My python code looks like this:
import serial
import io
class mySerial:
def __init__(self, port, baud_rate):
self.serial = serial.Serial(port, baud_rate, timeout=1)
self.serial_io_wrapped = io.TextIOWrapper(io.BufferedRWPair(self.serial, self.serial))
# receive message via serial
def read(self):
read_out = None
if self.serial.in_waiting > 0:
read_out = self.serial_io_wrapped.readline()
return read_out
# send message via serial
def write(self, message):
self.serial.write(message)
# flush the buffer
def flush(self):
self.serial.flush()
commandToSend = 'H'
ser = mySerial('COM9', 115200)
ser.flush()
ser.write(str(commandToSend).encode() + b"\n")
while True:
incomingMessage = ser.read()
if incomingMessage is not None:
print(incomingMessage)
Any help would be much appreciated.
You need to wait for new data after each line. Based on that, your read method need to be modified as below:
def read(self):
read_out = None
timeout = time.time() + 0.1
while ((self.serial.in_waiting > 0) and (timeout > time.time())):
pass
if self.serial.in_waiting > 0:
read_out = self.serial_io_wrapped.readline()
return read_out

Error when making a socket chat

I am making a chat using the socket library in python, it works, only half way though, when you netcat onto what I am using as a channel I am able to send messages and the other terminal is able to receive them, but, when that terminal sends a message (typing text, then hit enter) I do not receive it through the python script. So I ran it raw in the following way:
python shell:
import socket
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("127.0.0.1",8000)
sock.listen(2)
(client, (ip,port))=sock.accept()
Terminal:
nc 127.0.0.1 8000
This worked and to send or receive in the python shell all I had to do was type: sock.send("message") or sock.recv(2012)
Here is My code:
#!/bin/python
import socket
import subprocess
from subprocess import Popen, PIPE
import time
class color:
r = '\033[31m'
g = '\033[32m'
d = '\033[0m'
b = '\033[94m'
p = '\033[35m'
def clear():
print('\n' * 100)
chat_clients = []
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clear()
def chatting_on_serverr():
(client, (ip, port))=sock.accept()
def chatting_on_server():
message = raw_input("Send Message: ")
client.send(message + '\n')
client.recv(2012)
chatting_on_server()
chatting_on_server()
def make_channel():
print color.b + '[+] '+color.d+'Welcome to the chat server'+color.b+' [+]'
host = raw_input("Channel Name: ")
port = input("Channel Access Key: ")
clear()
print color.p + "[info] "+color.b+"Making %s" % host
time.sleep(1)
sock.bind((host,port))
sock.listen(3)
print color.g + "[+] "+color.d+"Channel Made"+color.g+" [+]"+color.d
print("[info]: Waiting for people to join your channel...")
global chatting_on_serverr
global chatting_on_server
chatting_on_serverr()
clear()
make_channel()
I cannot reproduce this on my machine because of network limitations but I recommend you to look at this tutorial of a Python chat client and server. It will explain a lot about sockets and networking.
Beside that you shouldn't define globals with the same name as functions in your code. It might override their declaration. Another thing is the function inside the function. You can write that function like that:
def chatting_on_server():
client, (ip, port) = sock.accept()
while True:
message = raw_input("Send Message: ")
client.send(message + '\n')
client.recv(2012)
And you will get the same functionality. Also, you risk yourself with a stack overflow error because chatting_on_server calls itself forever.
Good luck!
All that was needed to be done is to print the output of the .recv function
x = client.recv(2020)
print(x)

Pythons socket,recvfrom() not working on Rasperry Pi

I want to communicate with a Art-Net node (its a network gadget to convert UDP Art-Net packets into DMX output, that is used in stage and film lighing) with a raspberry pi, running python on raspbian.
There are 2 problems with that code below, one has to do with the pi:
When running the code on my windows computer, everything works fine.
When running the same code (except a change in the ip address for the socket.bind), the code sends the ArtPoll packets, the node in the network replies with the ArtPollReply, but these packets aren't received by the python script. The code hangs at the line "data, addr = self.sock.recvfrom(4096)" but nothing is giong to be received (there are packets to receive, the computer receives these packets at the same time).
Network config is okay, i checked everything. I checked also another artnet python thing, that worked - so there is no problem with the network interface itself.
Here is the whole demo code, that should demonstrate the problem.
import socket
import struct
import threading
import time
class PollThread(threading.Thread):
def __init__(self, artnet):
threading.Thread.__init__(self)
self.artnet = artnet
def run(self):
while self.artnet.running:
#break
time.sleep(3)
print self.artnet.nodes_ip
self.artnet.ArtPoll()
print "EXIT POLL THREAD"
class ArtNet(threading.Thread):
nodes_ip = []
nodes_data = []
running = True
def __init__(self):
threading.Thread.__init__(self)
self.pollthread = PollThread(self)
ip = "10.0.0.2"
self.header_artpoll = self.set_Header_ArtPoll()
#open socket
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.error, msg:
print 'Failed to create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
print '[INFO] Socket Created %s' % ip
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #Enable Broadcast
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #Diable Port blocking when reuse this port
self.sock.bind((ip, 6454))
def run(self):
self.pollthread.start()
while self.running:
print "RECEIVING...."
data, addr = self.sock.recvfrom(4096)
print "RECEIVED DATA!"
print addr
opcode = struct.unpack('<H', data[8:10])[0]
if opcode == 0x2000:
self.HandleArtPollReply(addr[0], data)
#self.artnet_handler.ArtPollReply()
if opcode == 0x2100:
self.HandleArtPollReply(addr[0], data)
print "EXIT ARTNET THREAD"
def set_Header_ArtPoll(self):
header = []
header.append("Art-Net\x00") #ID
header.append(struct.pack('<H', 0x2000)) #OpCode
header.append(struct.pack('>H', 14)) #ProtVer
header.append(struct.pack('>H', 0b00000000)) #TalkToMe
header.append(chr(0xe0)) #Priority
header = "".join(header)
return header
def HandleArtPollReply(self, ip, data):
self.nodes_ip.append(ip)
self.nodes_data.append(data)
def ArtPoll(self):
self.nodes_ip = []
self.nodes_data = []
self.sock.sendto(self.header_artpoll, ('<broadcast>', 6454))
self.sock.sendto(self.header_artpoll, ('10.255.255.255', 6454))
self.sock.sendto(self.header_artpoll, ('2.255.255.255', 6454))
if __name__ == '__main__':
artnet = ArtNet()
artnet.start()
s = raw_input()
artnet.sock.close()
artnet.running = False
print "MIAN EXIT"
EDIT:
Now I have additional information: if i bind to '', everything works fine, also on the pi.
self.sock.bind(('', 6454))
In the comments, I got the advice to use
self.sock.bind((socket.INADDR_ANY, 6454))
That throws an error:
self.sock.bind((socket.INADDR_ANY, 6454))
File "C:\Python27\lib\socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
TypeError: coercing to Unicode: need string or buffer, int found
That works for me in the first run, but it can be, i have to use multiple interfaces on the system for different tasks - so i may use the ip based bind to the interface to difference their service provided.
EDIT END
The second problem is, i don't know how to close the ArtNet() Class, because when i do, the thread hangs at "data, addr = self.sock.recvfrom(4096)" waiting for data. So I have to break this command. My idea is to send some data to the machine to unblock that thing....
EDIT:
I already use this self.sock.close() and the thread keeps running after close()

How to Send/Receive SMS using AT commands?

Can anyone help me to send and receive SMS using AT commands in Python?
In case it matters, I'm using Fedora 8.
Which phone will be better with Linux (Nokia, Sony Ericson, Samsung,.....)?
Will all phones support sending and receiving SMS using AT commands?
Here's some example code that should get you started (in Python 3000):
import time
import serial
recipient = "+1234567890"
message = "Hello, World!"
phone = serial.Serial("/dev/ttyACM0", 460800, timeout=5)
try:
time.sleep(0.5)
phone.write(b'ATZ\r')
time.sleep(0.5)
phone.write(b'AT+CMGF=1\r')
time.sleep(0.5)
phone.write(b'AT+CMGS="' + recipient.encode() + b'"\r')
time.sleep(0.5)
phone.write(message.encode() + b"\r")
time.sleep(0.5)
phone.write(bytes([26]))
time.sleep(0.5)
finally:
phone.close()
You need to do two additional things:
Encode the message in the appropriate format (mostly GSM 03.38, there's a handy translation table at unicode.org). If you really don't care about any characters other than ASCII, you can just check if every character is in string.printable.
Check the length of the message (I'm not sure if it's to do with the encoding, but it's sometimes 140 characters, sometimes 160).
You can use phone.readall() to check for errors, but it's best to make sure your message is OK before you send it off to the phone. Note also that the sleeps seem to be necessary.
Most phones will understand this. In order to get my old Nokia C5 to open up the serial connection, I had to select "PC Suite" from the menu that pops up when you insert the USB cable. This should work equally well over Bluetooth.
The code uses the PySerial package, available for python 2 and 3.
See also:
How do i go about writting a program to send and receive sms using python?
to see send sms using At command this will help.
import serial
import time
class TextMessage:
def __init__(self, recipient="+2348065777685", message="TextMessage.content not set."):
self.recipient = recipient
self.content = message
def setRecipient(self, number):
self.recipient = number
def setContent(self, message):
self.content = message
def connectPhone(self):
self.ser = serial.Serial('COM70', 460800, timeout=5, xonxoff = False, rtscts = False, bytesize = serial.EIGHTBITS, parity = serial.PARITY_NONE, stopbits = serial.STOPBITS_ONE)
time.sleep(1)
def sendMessage(self):
self.ser.write('ATZ\r')
time.sleep(1)
self.ser.write('AT+CMGF=1\r')
time.sleep(1)
self.ser.write('''AT+CMGS="''' + self.recipient + '''"\r''')
time.sleep(1)
self.ser.write(self.content + "\r")
time.sleep(1)
self.ser.write(chr(26))
time.sleep(1)
def disconnectPhone(self):
self.ser.close()
sms = TextMessage("+2348063796720","Mummy i sent this message from my computer")
sms.connectPhone()
sms.sendMessage()
sms.disconnectPhone()
print "message sent successfully"
To recieve sms using At command this should help
import serial
import time
import sys
class HuaweiModem(object):
def __init__(self):
self.open()
def open(self):
self.ser = serial.Serial('COM70', 406800, timeout=5)
self.SendCommand('ATZ\r')
self.SendCommand('AT+CMGF=1\r')
def SendCommand(self,command, getline=True):
self.ser.write(command)
data = ''
if getline:
data=self.ReadLine()
return data
def ReadLine(self):
data = self.ser.readline()
print data
return data
def GetAllSMS(self):
self.ser.flushInput()
self.ser.flushOutput()
command = 'AT+CMGL="REC UNREAD"\r\n'#gets incoming sms that has not been read
print self.SendCommand(command,getline=True)
data = self.ser.readall()
print data
h = HuaweiModem()
h.GetAllSMS()
Talking to the phone is easy. You just need to open the appropriate /dev/ttyACM* device and talk to it. Which phone is trickier. Any phone that supports "tethering" and the full AT command set for SMS messages should be fine.
I would suggest replace the time.sleep with condition loop waiting for the response from the modem "OK" before continue next state.

Categories

Resources