pyserial receiving wrong data with the None - python-3.x

when I write the bytes into serial, I get the data which I want, but there's a None appearing that my serial doesn't have this one.How can I delete the "None"?
Thanks!
#encoding = utf-8
import serial
def getValues():
ser = serial.Serial('COM3', baudrate=9600, timeout=1)
str = 'ZREADMACS'
ser.write(bytes(str, encoding='utf8'))
data = ser.readline()
print(data)
while 1:
# data = ser.readline()
# if data:
# print(str(data)[2:63])
# else:
# print(getValues())
userInput = input('Are you kidding me?')
if userInput == "1":
print(getValues())
output like this, but I don't want "None".
Are you kidding me?1
b'client:TESTR~~address:R0003~~radiation:01000~~voltage:21000~~current:21000~~temprature:01000~~Li_power:02000~~time_delay:00010~~acs_712_zero:00000~~'
None
Are you kidding me?1
b'client:TESTR~~address:R0003~~radiation:01000~~voltage:21000~~current:21000~~temprature:01000~~Li_power:02000~~time_delay:00010~~acs_712_zero:00000~~'
None

On your code you call print twice.
On the first time you call it with data and data is assigned to the readline result.
On the second time, you call it directly on the getValues() result.
The problem here is that getValues() returns nothing so python translates it as None and then you print it.
If you remove the last print it will be good.
You can also add return data to your getValues() function.

Related

Python: Printing data and receiving user input simultaneously

I want to be able to receive user input and print stuff simultaneously, without them interfering. Ideally, that would be printing regularly and having the user type input to the bottom of the terminal window, for example:
printed line
printed line
printed line
printed line
printed line
(this is where the next print would happen)
Enter Input: writing a new input...
This should look like a chat app or something of that sort.
If there is no good way to do that, any way to print above the input line would be amazing too.
Thanks!
Sadly it is not very feasible to both take input and give output in python, without importing modules to directly interact with the OS.
But you can can get pretty close to it with this code:
import curses
import random # for random messages
#this should be async
def get_message():
message = [str(random.randint(0,9)) for i in range(15)]
return "".join(message)
def handle_command(cmd): # handle commands
if cmd=="exit":
exit(0)
def handle_message(msg): # send a message
raise NotImplementedError
def draw_menu(stdscr):
stdscr.erase()
stdscr.refresh()
curses.raw()
k = 0
typed=""
while True:
# Initialization
stdscr.erase()
height, width = stdscr.getmaxyx()
stdscr.addstr(0, 0, "Welcome to chat app")
msg = get_message()
if msg: # add a message if it exists
stdscr.addstr(1, 0, msg)
if k==ord("\n"): # submit on enter
if typed.startswith("/"): # execute a command
typed = typed[1:]
handle_command(typed)
elif typed.startswith("./"): # bypass commands with a dot
typed = typed[1:]
handle_message(typed)
else:
handle_message(typed) # send the message
typed = ""
elif k==263: # Backspace
typed = typed[:-1] # erase last character
stdscr.addstr(height-1, 0, typed)
elif k==3: # Ctr+C
typed="" # Delete the whole string
stdscr.addstr(height-1, 0, typed)
elif k!=0:
typed += chr(k) # add the char to the string
stdscr.addstr(height-1, 0, typed)
stdscr.refresh() # refresh
# Wait for next input
k = stdscr.getch()
def main():
curses.wrapper(draw_menu)
if __name__ == "__main__": # dont import
main()
the only thing that is to do to update the messages is to type a new char.
And I do not recommend you to build a chat in the terminal for anything other then educational value (trust me I tried it).
It would be better if you tried it using a web platform (e.g. Tauri or Electron)
Also the code cannot:
insert automatic line breaks (it errors)
send any messages (must implement yourself)
show any user names (must implement yourself)

Thread Save Serial Connection in Telepot (Python)

I have a serial device (Arduino) regularly outputting log data, which shold be written in a Log file. Also the device takes spontaneous commands over serial. I send the commands to a Raspberry over Telegram, which are handled and sent to the arduino by Telepot, which runs in a separate thread.
How can I make sure that the two processes get along with each other?
I am a complete Beginner in Multithreading.
Here is a shortened version of my Code:
import time
import datetime
import telepot
import os
import serial
from time import sleep
ser = None
bot = None
def log(data):
with open('logfile', 'w') as f:
file.write("Timestamp" + data)
#The handle Function is called by the telepot thread,
#whenever a message is received from Telegram
def handle(msg):
chat_id = msg['chat']['id']
command = msg['text']
print( 'Command Received: %s' % command)
if command = '/start':
bot.sendMessage(chat_id, 'welcome')
elif command == 'close_door':
#This serial write could possibly happen while a
#ser.readline() is executed, which would crash my program.
ser.write("Close Door")
elif command == 'LOG':
#Here i should make sure that nothing
#is waiting from the Arduino
#so that the next two Serial lines are the Arduinos
#respoonce to the "LOG" command.
#and that hanlde is the only
#function talking to the Serial port now.
ser.write("LOG")
response = ser.readline()
response += "\0000000A" + ser.readline()
#The Arduinos response is now saved as one string
#and sent to the User.
bot.sendMessage(chat_id, response)
print("Command Processed.")
bot = telepot.Bot('BOT TOKEN')
bot.message_loop(handle)
ser = serial.Serial("Arduino Serial Port", 9600)
print( 'I am listening ...')
while True:
#anything to make it not run at full speed (Recommendations welcome)
#The log updates are only once an hour.
sleep(10)
#here i need to make sure it does not collide with the other thread.
while ser.in_waiting > 0:
data = ser.readline()
log(data)
This code is not my actual code, but it should represent exactly what I'm trying to do.
My last resort would be to put the serial code in the threads loop function, But this would require me to change the libary which would be ugly.
I looked up some stuff about Queues in Asincio, and locking functions. However i don't really understand how to apply that. Also I don't use the async telepot.
After reading more on locking and threads, I found an answer with help of the links provided in this Question: Locking a method in Python?
It was often recommended to use Queues, however I don't know how.
My solution (code may have errors, but the principle works)
import time
import random
import datetime
import telepot
import os
import serial
from time import sleep
#we need to import the Lock from threading
from threading import Lock
ser = None
bot = None
def log(data):
with open('logfile', 'w') as f:
file.write("Timestamp" + data)
#create a lock:
ser_lock = Lock()
#The handle Function is called by the telepot thread,
#whenever a message is received from Telegram
def handle(msg):
#let the handle function use the same lock:
global ser_lock
chat_id = msg['chat']['id']
command = msg['text']
print( 'Command Received: %s' % command)
if command == '/start':
bot.sendMessage(chat_id, 'welcome')
elif command == 'close_door':
#This serial write could possibly happen while a
#ser.readline() is executed, which would crash my program.
with ser_lock:
ser.write("Close Door")
elif command == 'LOG':
#Here i should make sure that nothing
#is waiting from the Arduino
#so that the next two Serial lines are the Arduinos
#respoonce to the "LOG" command.
#and that hanlde is the only
#function talking to the Serial port now.
#the lock will only be open when no other thread is using the port.
#This thread will wait untill it's open.
with ser_lock:
while ser.in_waiting > 0:
data = ser.readline()
log(data)
#Should there be any old data, just write it to a file
#now i can safely execute serial writes and reads.
ser.write("LOG")
response = ser.readline()
response += "\0000000A" + ser.readline()
#The Arduinos response is now saved as one string
#and sent to the User.
bot.sendMessage(chat_id, response)
print("Command Processed.")
bot = telepot.Bot('BOT TOKEN')
bot.message_loop(handle)
ser = serial.Serial("Arduino Serial Port", 9600)
print( 'I am listening ...')
while True:
#anything to make it not run at full speed (Recommendations welcome)
#The log updates are only once a
sleep(10)
#here i need to make sure it does not collide with the other thread.
with ser_lock:
while ser.in_waiting > 0:
data = ser.readline()
log(data)

problems to handle more than one (return) parameter in main()

I'm rewriting an old keyword-scanner from Python2 to Python3 and have problems to handle more than one return parameter in my final main()-function.
def scanner_pref():
dork = input('Dork: ')
number = input('Number of sites: ')
return dork, number
So, I need to return dork and number to the next function
def scanner(dork, number):
url = "http://www.google.de/search"
payload = {'q': dork, 'start':'0', 'num': int(number) *10}
[..]
so the scanner can proceed with the given parameters of payload.
But when I try to write the main()-function, it can't handle the scanner-function, because it suddendly requires the numbers parameter. see below
def main():
pref = scanner_pref()
scan = scanner(pref) <--
parser(h3tag=scan)
I don't really understand why scan = scanner(pref, ?) requires the number parameter when it receives the information from the scanner(pref) above and doesn't really care about the dork-parameter.
If I remove "number" from scanner_pref(), move it back to scanner(..) it works fine and no error or warning message appears.
def scanner_pref():
dork = input('Dork: ')
return dork
#
def scanner(dork, number):
url = "http://www.google.de/search"
number = ("Number of sites: ")
payload = {'q': dork, 'start':'0', 'num': int(number) *10}
#
def main():
pref = scanner_pref()
scan = scanner(pref)
parser(h3tag=scan)
works fine and without problems
scanner(dork, number) takes two arguments.
When you call pref = scanner_pref() the values dork and number are stored in perf as a tuple. When you pass pref to scanner you are still only passing one argument, a tuple with two values.
you have two easy options
pref_dork, pref_number = scanner_pref()
scan = scanner(pref_dork, pref_number)
or
pref = scanner_pref()
scan = scanner(pref[0],perf[1])

TCP connection is not giving me output second time

I have made server/client with TCP connection, which converts bin to dec or dec to bin and returns the output to the client. The program is running fine with one iteration
Problem
When I want to get the output(conversion) again without quitting the program, I enter a number and it sends that number to the server, the server doesn't responds back, the cursor starts blinking and shows no output. I waited for like 5 min and nothing happened.
I don't understand why this is happening
PS: pardon my code, I know it can be improved. I just want it to show output again and again
Here's my code. Assume all libraries are imported and all conversion functions are running fine and included
SERVER
print('The server is ready')
message = "yes"
connectionSocket, addr = serverSocket.accept()
while 1:
while(message == "yes"):
print(connectionSocket.getpeername())
sentence = connectionSocket.recv(4096).decode('utf-8')
number = connectionSocket.recv(4096).decode('utf-8')
# binary to decimal conversion
if(sentence == 'bin_to_dec'):
digits = str(binToDec(number))
connectionSocket.send(digits.encode('utf-8'))
# decimal to binary conversion
elif(sentence == 'dec_to_bin'):
numbers = str(decToBin(number))
connectionSocket.send(numbers.encode('utf-8'))
# If everything fails
else:
print("Wrong input!")
connectionSocket.close()
if(connectionSocket.recv(4096).decode('utf-8') == "no"):
break
connectionSocket.close()
Client
clientSocket.connect((serverName, serverPort))
# flag to check if the user wants to end the input
end_everything = False
again = 'yes'
while(end_everything == False):
# while the user wants to input again
while(again.lower() == "yes"):
# input
sentence = str(input('bin_to_dec or dec_to_bin >: '))
# checking whether the input is correct
if(sentence.lower() == "bin_to_dec" or sentence.lower() == "dec_to_bin"):
# inputting the number to convert
number = str(input("which number or digits you want to convert >: "))
#encodes the input and sends it to the server
clientSocket.send(sentence.encode('utf-8'))
clientSocket.send(number.encode('utf-8'))
#resonse from the server
modifiedSentence = clientSocket.recv(4096)
response = modifiedSentence.decode('utf-8')
#prints that response
print('From Server: ', response)
#prompting user, if they want to input again
message = input("type 'yes' or 'no' if you want to input again: ")
if(message.lower() == "yes"):
#clientSocket.send(message.encode())
continue
elif(message.lower() == "no"):
clientSocket.send(message.encode('utf-8'))
again = 'no'
else:
print("Please enter correct input")
else:
print("Not valid input!")
break
clientSocket.close()
So first of all, yes, your close is a little rough. It's actually a little difficult to follow, mainly because I'm not as used to python probably. "while 1" always hurts, but I do it too.
So, my first guess is the "serverSocket.accept()" call on the server. It looks like you accept a connection, receive data, send, and then loop around and accept a new connection. Client side expects to keep sendings messages over and over.
You probably want that serverSocket.accept() moved to the outside while loop instead, so it keeps reading from your connection until it closes down.

Python3 socket cannot decode content

I'm facing a strange issue. I cannot decode the data received through a socket connection while it's working with the same code in python 2.7. I know that the data type received in python 2 is a string an bytes in python 3. But I don't understand why I'm receiving an error when I try to decode.
I'm sending exactly the same datas(copy/paste to be sure) except that I need to perform .encode() for python 3 to avoid to received "TypeError, a bytes-like object is required, not 'str' "
Python2:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(15)
s.connect((SERVERIP, SERVERPORT))
s.send(message)
data = ''
while True:
new_data = s.recv(4096)
if not new_data:
break
data += new_data
s.close()
Python 3
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(15)
s.connect((SERVERIP, SERVERPORT))
s.send(message)
data = ''
while True:
new_data = s.recv(4096)
if not new_data:
break
data += new_data.decode('utf-8') #same result with new_data.decode()
s.close()
Python 2 new_data content:
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x00\x05\xc1\xdd\x12B#\x18\x00\xd0\x07r\xa3\xb6\xfdv]t\xa1T&\xb5d\x91\xd1tA\x98]F\xfeB\x1a\x0f\xdf9yu\x10s\xa3\xa29:\xdbl\xae\xe9\xe8\xd9H\xc8v\xa8\xd0K\x8c\xde\xd7\xef\xf9\xc4uf\xca\xfd \xdd\xb7\x0c\x9a\x84\xe9\xec\xb7\xf1\xf3\x97o\\k\xd5E\xc3\r\x11(\x9d{\xf7!\xdc*\x8c\xd5\x1c\x0b\xadG\xa5\x1e(\x97dO\x9b\x8f\x14\xaa\xddf\xd7I\x1e\xbb\xd4\xe7a\xe4\xe6a\x88\x8b\xf5\xa0\x08\xab\x11\xda\xea\xb8S\xf0\x98\x94\x1c\x9d\xa24>9\xbai\xd3\x1f\xe6\xcc`^\x91\xca\x02j\x1aLy\xccj\x0fdVn\x17#\xb0\xc1#\x80hX#\xb0\x06\n\x0b\xc0\xf2x\xfe\x01?\x05\x1f\xc1\xc5\x00\x00\x00'
Python3 new_data content:
b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x00\x05\xc1\xdb\x12B#\x00\x00\xd0\x0f\xf2\xc0\xda\xb5\xcbC\x0f"-\xb9gPM\x0f\x85&\x8b)\xb7\x1d\x1a\x1f\xdf9\xe3\xbc\xbe\xfd\x9e\xd9A\xe3:\x851,\xcf\xc4\xe5\x865|\xa5\xcb\xbb\xcbs\xa8\x8f\xcc\x1b\xf7\x06\xc5\x8f\xfa\xba\x84\xd8>\xea\xc0\xa5b\xe6\xceC\xea\xd0\x88\xebM\t\xd7\xf8\xc1*#hI\xd6F\x80\xb3B[\xa7\x99\x91\xbe\x16%Q\xf5\x1d(\xa0\x93\x87\n\x13\xbe\x92\x91\xcc\xbfT\x98b\xd3\x0b=\xc0\xd5\xb3\xdf}\xcc\xc9\xb1\xe4\'\xb1\xe25\xcc{tl\xe5\x92\xf34x\xd5\xa1\xf9K\xa4\xa8k\xa8 dU\xd7\x1e\xce\xb4\x02\xean\xc3\x10#\x05\x13L\x14\xa0(H\xd2d\xb8a\xbc\xdd\xee\x7f\x1b\xe5\xf1\xd2\xc5\x00\x00\x00'
And so when in python3 I'm receiving this error when I try to decode:
'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
The data received are not the same. The difference start after 'x12B#'. Someone has an explanation?
I'm not managing the server side so don't ask me to check this side!
Thanks,
Matthieu
For Python 3 you need to work with bytes, the data you have is not a text string so don't try and interpret it as one.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(15)
s.connect((SERVERIP, SERVERPORT))
s.send(message)
data = b''
while True:
new_data = s.recv(4096)
if not new_data:
break
data += new_data
s.close()
That should be all you need to receive the data: start with an empty bytes object created using b'' or just bytes(), but you will also have to be aware you are working with bytes when you come to process the data so that code will probably need changing as well.
You next step in processing this is probably:
import gzip
text = gzip.decompress(data)
and at this point it may be appropriate to change that to:
text = gzip.decompress(data).decode('ascii')
using whatever encoding is appropriate here (the sample data you posted above only contains ascii when decompressed so that might be all you need, or you might want utf-8 or some other encoding but you'll have to find out what was used to encode the data as you shouldn't attempt to guess). However it looks like it contains some pipe-separated fields so you might want to split the fields first and decode or otherwise process them individually:
fields = gzip.decompress(b).split(b'|')

Resources