I am using Python 3.7.5 with the latest version of serial library. I am trying to make an RFID authentication device via python and arduino. User has to scan their ID in the RFID connected to the arduino and the arduino must send the UID to the python software. In my laptop, a thread listening for serial is running. It checks the UID and it will send 'O' if it is allowed and 'X' if it is not. In the arduino, the program then waits if there is data sent through the serial then checks the input if it is 'O' or not. If the RX is 'O' then the LED must light green, otherwise red.
My problem is that when I first scan the CORRECT uid, it goes green, no problem. If I scan another CORRECT uid it goes green again, no problem. If I scan an INCORRECT uid, it goes green, but in my python code it SHOULD BE RED. Then if I scan a CORRECT uid, it goes RED whereas is should be GREEN. I tried adding delays to both arduino and python to wait for the previous input to clear and also tried flushing after transmission with no luck.
tl;dr The arduino is outputting results ONE uid scan late and I don't know what else to do.
Python:
# Reads data from the serial monitor without interrupting the main thread
from serial import Serial
import time
from threading import Thread
class SerialListener:
def __init__(self, baudrate=9600, timeout=1):
try:
self.ser = Serial('/dev/ttyACM0', baudrate, timeout=timeout)
except:
self.ser = Serial('/dev/ttyACM1', baudrate, timeout=timeout)
self.stopped = False
self.paused = False
self.stream = ''
time.sleep(1) # Wait for serial buffer to reset
def start(self):
Thread(target=self.update, args=()).start()
return self
def update(self):
if not self.paused:
while True:
if self.stopped:
self.ser.close()
print("Serial Thread Stopped")
print("Serial Port Closed")
break
try:
self.stream = self.ser.readline().decode('utf-8')
except:
self.stream = self.ser.readline().decode('ascii')
self.stream = self.stream.rstrip()
def stop(self):
self.stopped = True
def pause(self):
self.paused = True
def flush(self):
self.ser.flush()
def readDistance(self):
try:
return float(self.stream)
except:
return -1 # Returns -1 if there is an error in reading
def readRFID(self):
return self.stream
def write(self, msg):
self.ser.write(msg.encode())
if __name__ == "__main__": # FOR DEBUGGING ONLY
uno = SerialListener().start()
uno.flush()
print("Serial Started")
uid = ''
while True:
uid = uno.readRFID()
if uid is not '':
uno.flush()
time.sleep(0.1)
if uid == "5BEE9F0D":
uno.write('O')
print("SHOULD BE GREEN")
else:
uno.write('X')
print("SHOULD BE RED")
print(uid)
uno.stop()
Arduino:
#include <MFRC522.h>
#define GREEN_LED 6
#define RED_LED 7
#define BUZZER 8
MFRC522 rfid(10, 9);
unsigned long timer = 0;
bool readStatus = false;
void setup() {
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
Serial.begin(9600);
SPI.begin();
rfid.PCD_Init();
for(int i = 0; i < 10; i++)
Serial.write('\n');
delay(5);
digitalWrite(RED_LED, HIGH);
}
void loop() {
while(!readStatus){
if(rfid.PICC_IsNewCardPresent()){
if(rfid.PICC_ReadCardSerial()){
byte uid[rfid.uid.size];
if((millis() - timer) > 1000){
for(int i = 0; i < rfid.uid.size; i++)
uid[i] = rfid.uid.uidByte[i];
for(int i = 0; i < sizeof(uid); i++){
if(uid[i] < 0x10)
Serial.print('0');
Serial.print(uid[i], HEX);
}
Serial.println();
readStatus = true;
timer = millis();
}
Serial.flush();
}
}
}
if(readStatus){
while(!Serial.available());
char rx = 'X';
while(Serial.available()){
rx = Serial.read();
}
if(rx == 'O'){
digitalWrite(GREEN_LED, HIGH);
digitalWrite(RED_LED, LOW);
tone(BUZZER, 2500);
delay(100);
noTone(BUZZER);
readStatus = false;
}
else{
digitalWrite(RED_LED, LOW);
digitalWrite(GREEN_LED, LOW);
tone(BUZZER, 1000);
delay(50);
noTone(BUZZER);
delay(30);
tone(BUZZER, 1000);
delay(50);
noTone(BUZZER);
digitalWrite(RED_LED, HIGH);
readStatus = false;
}
}
}
Output:
Serial Started
SHOULD BE RED
05520320 // it is red
SHOULD BE RED
05520320 // it is red
SHOULD BE GREEN
5BEE9F0D // it is red
SHOULD BE GREEN
5BEE9F0D // it is green
SHOULD BE RED
05520320 // it is green
if(rx == 'O') ... else
is problematic because it does not validate one case of the input before the action is performed. BTW SPI is not a "serial port" . – sawdust