The problem is, that I use a device (ISDT CM1620) for charging my batteries.
I want to automate the start of the charging via a simple button.
The device offers a simple protocol described on their page https://www.isdt.co/support?lang=en at "Open source"
I tried Python with "pyserial" and Kotlin with "jSerialComm" and got the same result.
If I run it on a Windows machine it works without any problem, but as soon as I switch to my raspberry with raspbian or to my PC with ubuntu it no longer works reliable.
As soon as I receive longer payloads all or parts of the message I receive are dropped.
What I have found out is that the device automatically detects the baud rate and windows using the "usbser" driver to handle the communication. On my raspberry pi, I just plugged it in and used the "/dev/ttyACM0" file for communication.
I also tried flow control (xonxoff, rtscts, dsrdtr and none), but it did not solve the problem.
Have anyone an idea what I am missing?
Here is a part of my python implementation:
import serial
import argparse
import io
import sys
def isNL(str):
return str == "\n" or str == "\r"
class Charger:
def __init__(self, port):
self.ser = serial.Serial(port, 2560000, timeout = 0.2)
self.sio = io.TextIOWrapper(io.BufferedRWPair(self.ser, self.ser), "utf-8")
def readFrame(self):
text = ""
byte = ""
last = ""
while not(isNL(byte) and isNL(last)):
text += byte
last = byte
byte = self.sio.read(1)
if byte == "":
return []
if text == "":
return []
return text.strip().split("\n")
def sendCommand(self, line):
encoded_cmd = "#" + line + "\r\n"
self.sio.write(encoded_cmd)
self.sio.flush()
def request(self, line):
for i in range(300):
self.sendCommand(line)
frame = self.readFrame()
if len(frame) > 0:
return frame
print("retry")
sys.exit(-1)
def login(self):
block = self.request("login null")
return block[1:]
def hello(self):
block = self.request("hello")
return block[1:]
def print_serial(name):
global ser
print(name)
charger = Charger(name)
status = charger.hello() #waits indefinitely because it waits for a message that has been dropped and tries again after a timeout and so on.
print(status)
ap = argparse.ArgumentParser()
ap.add_argument("-p","--port",required = True, help = "Enter Port Name")
args = vars(ap.parse_args())
PORT = args['port']
print_serial(PORT)
EDIT:
Due to the fact, that the software works find on Windows i have installed windows 10 on my raspberry.
But it seems it does not depend on the operating system, because the same effects of dropping bytes and missing frames appear there as well. Until now the implementation and shipped software from the manufacturer only worked on that one windows laptop, which I can not use as my server.
Related
I am currently trying to use pyserial to read the values from my handheld tachometer, the specific model is the DT-2100.
I am using python 3 and my current code looks like this:
# Imports
import serial
import time
import io
# Coding section
# Setting Parameters
port = "COM3"
baud = 38400
data = []
info = 0
# Setting the port location, baudrate, and timeout value
ser = serial.Serial(port, baud, timeout=2)
# Ensuring that the port is open
if ser.isOpen():
print(ser.name + ' is open...')
# trying to read a single value from the display
#input("Ensure that the DT-2100 is turned on...")
info = ser.write(b'CSD')
ser.write(b'CSD')
info_real = ser.readlines()
print()
print("The current value on the screen is: ", info)
print()
print("The real value on the screen is: ", info_real)
This is what I get back after running the code:
COM3 is open...
The current value on the screen is: 3
The real value on the screen is: []
Process finished with exit code 0
The main issue is that I should be getting the value that is displayed by the tachometer, which for this test was 0, but between my two attempted methods I got 3 and nothing.
Any help is greatly appreciated.
The zip file you linked to contained an xls file which seemed to detail all the commands.
All the commands seem to be wrapped in: <STX> cmd <CR>, so you are missing those.
The CSD command would need to be like this: ser.write(b'\x02CSD\r')
Similarly the reply is also wrapped in the same way and you would need to remove those bytes and interpret the rest.
I am trying to make a program which constantly reads data being sent from device using serial port to computer. In addition to this whenever I enter something it is sent to device.(My main aim is to make a serial terminal emulator).
I wrote following program but it waits for any input and does not constantly read data and display on screen sent by device as thought:
ser1 = serial.Serial(com_name_to_use, auto_baud, timeout=0, write_timeout=0)
while True:
try:
# Writing Section
inp_str1 = input() # + "\n"
str1 = inp_str1.encode(encoding="ascii")
ser1.write(str1)
time.sleep(0.03)
# Reading Section
bf = ser1.readline()
print(str(bf, encoding="utf-8"), end="")
except Exception as err1:
pass
Kindly, tell how to fix it.
I am working on a project, in which I have to interface multiple RFID Readers (I'm Using EM 18, With Serial out) with Raspberry Pi. I'm using an USB to TTL Converter to connect EM 18 to Raspberry Pi. I've connected two RFID Readers using USB to TTL Adapter.
This is my code for one station
Code
import serial, time
while True:
try:
print 'station one Is Ready!! Please Show your Card'
card_dataa = serial.Serial('/dev/ttyUSB0', 9600).read(12)
print card_dataa
continue
except serial.SerialException:
print 'Station 1 is Down'
break
My Issues are
I would like to get the readings from both the RFID Readers in the same program simultaneously.
I've two Programs with the above code, station1.py and station2.py.
Station1.py is for USB0 and Station2.py is for USB1.
I am executing the programs in different Terminal simultaneously.
For example station1.py in terminal 1 and station2.py in terminal 2. The program executes fine, but the readings are jumbled. For example, 6E0009D2CC79 and 4E0070792760 are the tag id's that i'm using for testing. if I'm executing only one program i'm getting the reading properly, but if I'm executing both programs simultaneously in two terminals I'm getting the tag Id's jumbled.
I want to combine both the readings in the same program.
Thanks in Advance
I'd recommend create a new Serial object once and reading multiple times, as needed:
import serial, time
try:
station1 = serial.Serial('/dev/ttyUSB0', 9600)
print 'station one Is Ready!! Please Show your Card'
except serial.SerialException:
print 'Station 1 is Down'
while True:
card_dataa = station1.read(12)
print card_dataa
Optionally you can set a timeout of 0:
import serial, time
try:
station1 = serial.Serial('/dev/ttyUSB0', 9600,timeout=0)
print 'station one Is Ready!! Please Show your Card'
except serial.SerialException:
print 'Station 1 is Down'
while True:
card_dataa = station1.read(12)
if len(card_dataa) > 0: print card_dataa
You should also easily be able to open 2 serial connections in the same program:
import serial, time
station1 = None
station2 = None
try:
station1 = serial.Serial('/dev/ttyUSB0', 9600,timeout=0)
print 'station 1 Is Ready!! Please Show your Card'
except Exception,e:
print 'Station 1 is Down',e
try:
station2 = serial.Serial('/dev/ttyUSB1', 9600,timeout=0)
print 'station 2 Is Ready!! Please Show your Card'
except Exception,e:
print 'Station 2 is Down',e
while True:
if station1 != None:
card_dataa1 = station1.read(12)
if len(card_dataa1) > 0: print card_dataa1
if station2 != None:
card_dataa2 = station2.read(12)
if len(card_dataa2) > 0: print card_dataa2
This means the 2nd reader would wait for the 1st reader to finish before printing, which is why fingaz recommended threading.
Here's a basic commented proof of concept for threading:
import threading,time,serial
#subclass threading.Thread
class RFIDSerialThread(threading.Thread):
SLEEP_TIME = 0.001 #setup sleep time (update speed)
#constructor with 3 parameters: serial port, baud and a label for this reader so it's easy to spot
def __init__(self,port,baud,name):
threading.Thread.__init__(self) #initialize this instance as a thread
self.isAlive = False #keep track if the thread needs to run(is setup and able to go) or not
self.name = name #potentially handy for debugging
self.data = "" #a placeholder for the data read via serial
self.station = None #the serial object property/variable
try:
self.station = serial.Serial(port,baud,timeout=0) #attempt to initialize serial
self.isAlive = True #and flag the thread as running
except Exception,e:
print name + " is Down",e #in case of errors print the message, including the station/serial port
def run(self): #this gets executed when the thread is started
while self.isAlive:
if self.station != None: self.data = self.station.read(12) #read serial data
time.sleep(RFIDSerialThread.SLEEP_TIME)
if __name__ == '__main__':
#initialize the two readers
station1 = RFIDSerialThread('/dev/ttyUSB0',9600,"station #1")
station2 = RFIDSerialThread('/dev/ttyUSB1',9600,"station #2")
#start the threads
station1.start()
station2.start()
while True:#continously print the data (if any)
if len(station1.data) > 0: print station1.name,station1.data
if len(station2.data) > 0: print station2.name,station2.data
Note that I haven't attached actual hardware to test, so this may not work as is, but should provide enough info to progress.
I would also suggest trying to physically distance the readers. Depending on the readers and their capabilities they may be interfering witch each other which might result in faulty data. In case you still have issues with jumbled data, I'd try to figure out where the problem is by taking some assumptions out.(e.g. is the issue a hardware (readers interfering, broken reader, loose USB connector, etc.) or software(serial port not properly initialized/flushed/etc.), taking one thing out at a time)
To have a concurrent flow, you can use the threading module. Here's a link to the documentation:
https://docs.python.org/2/library/threading.html
I'm trying to get the raw input of my keyboard in python. I have a Logitech gaming keyboard with programmable keys, but Logitech doesn't provide drivers for Linux. So i thought i could (try) to write my own driver for this. In think the solution could be something like:
with open('/dev/keyboard', 'rb') as keyboard:
while True:
inp = keyboard.read()
-do something-
English isn't my native language. If you find errors, please correct it.
Two input methods that rely on the OS handling the keyboard
import sys
for line in sys.stdin.readlines():
print line
This is one "simple" solution to your problem considering it reads sys.stdin you'll probably need a driver and if the OS strips stuff along the way it will probably break anyways.
This is another solution (linux only afaik):
import sys, select, tty, termios
class NonBlockingConsole(object):
def __enter__(self):
self.old_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
return self
def __exit__(self, type, value, traceback):
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, self.old_settings)
def get_data(self):
try:
if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
return sys.stdin.read(1)
except:
return '[CTRL-C]'
return False
data = ''
printed = ''
last = ''
with NonBlockingConsole() as nbc:
while 1:
c = nbc.get_data()
if c:
if c == '\x1b': # x1b is ESC
break
elif c == '\x7f': # backspace
data = data[:-1]
printed = data[:-1]
last = ''
sys.stdout.write('\b')
elif c == '[CTRL-C]':
data = ''
last = ''
sys.stdout.write('\n')
elif c == '\n': # it's RETURN
sys.stdout.write('\n')
# parse data here
data = ''
else:
data += (c)
last = c
sys.stdout.write(c)
Driver issue?
If none of the above work, you woun't be able to get the keys within Python.
Most likely you'll need an actual driver that can parse the data sent from the keyboard that is not a normal keyboard event on the USB stack, meaning.. This is way to low-level for Python and you're out of luck... unless you know how to build linux drivers.
Anyway, have a look at: http://ubuntuforums.org/showthread.php?t=1490385
Looks like more people have tried to do something about it.
Trying PyUSB
http://pyusb.sourceforge.net/docs/1.0/tutorial.html
You could try a PyUSB solution and fetch raw data from the USB socket, but again.. if the G-keys are not registered as "traditional" USB data it might get dropped and you won't recieve it.
Hooking on to the input pipes in Linux
Another untested method, but might work //Hackaday:
Logitech doesn't provide drivers for Linux. So i thought i could (try) to write my own driver for this.
Linux drivers are written in C; it's very low-level code and runs in kernel space.
I have a Python program that reads some parameters from an Arduino and stores it in a database. The serial port is set up and used like this:
ser = serial.Serial(port=port, baudrate=9600)
ser.write('*')
while 1 :
ser.write('*')
out = ''
# Let's wait one second before reading output (let's give device time to answer).
time.sleep(1)
while ser.inWaiting() > 0:
out += ser.read(1)
if out != '':
etc ... handling data
(The Arduino is set up so when it receives a star, it sends back a data string.) I would like to rewrite this as a daemon, so I am using the python-daemon library. In the init-part, I just define the port name, and then:
def run(self):
self.ser = serial.Serial(port=self.port,baudrate=9600)
while True:
self.ser.write('*')
out = ''
# Let's wait one second before reading output (give device time to answer).
time.sleep(1)
while self.ser.inWaiting() > 0:
out += self.ser.read(1)
if out != '':
etc ...
Everything is equal, except that I am now doing the serial handling within an App-object. The first version runs fine, when I try to run the latter, I get
File "storedaemon.py", line 89, in run
while self.ser.inWaiting() > 0:
File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 435, in inWaiting
s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str)
IOError: [Errno 9] Bad file descriptor
I am not able to see what has changed - except that I have tossed the code inside a new object. I have tried both to do the initialisation in init and in run, but I end up with the same result.
(The complete scripts are available at hhv3.sickel.net/b/storedata.py and hhv3.sickel.net/b/storedaemon.py.)
During the daemonization of your app, all file handlers are closed except stdin, stderr and stdout. This includes the connection to /dev/log, which then fails with the fd error (so it looks like this has nothing to do with the serial fd, but instead with the handler's socket).
You need either to add this FD to the exclusion list:
class App():
def __init__(self):
...
self.files_preserve = [handler.socket]
...
Or alternatively, set up the handler after the daemon process forked:
class App():
def run(self):
handler = logging.handlers.SysLogHandler(address = '/dev/log')
my_logger.addHandler(handler)
my_logger.debug(appname+': Starting up storedata')
...
Both version ran fine during my tests.