2023-10-31 17:54:21 +00:00
|
|
|
import serial
|
|
|
|
import requests
|
|
|
|
import binascii
|
2023-10-31 21:09:34 +00:00
|
|
|
import threading
|
|
|
|
import time
|
2023-10-31 21:55:09 +00:00
|
|
|
from requests.exceptions import RequestException, ConnectionError
|
2023-10-31 17:54:21 +00:00
|
|
|
|
2023-10-31 21:47:31 +00:00
|
|
|
# Constants
|
|
|
|
SERIAL_PORT = '/dev/tty.usbserial-0001'
|
|
|
|
BAUD_RATE = 9600
|
2023-10-31 23:20:39 +00:00
|
|
|
TINANCE2_READER_IDENTIFIER = "CNC-READER-1"
|
2023-10-31 21:47:31 +00:00
|
|
|
TINANCE2_READER_ACCESS_KEY = "4f95166a-8a15-4963-bad8-35c7047b4269"
|
|
|
|
API_BASE_URL = 'http://localhost:8000/accesscontrol/api/'
|
|
|
|
|
|
|
|
# Reader configuration
|
2023-10-31 21:43:38 +00:00
|
|
|
reader_info = {
|
|
|
|
"enabled": False,
|
|
|
|
"mode": None
|
|
|
|
}
|
2023-10-31 17:54:21 +00:00
|
|
|
|
2023-10-31 21:47:31 +00:00
|
|
|
# Headers for API requests
|
|
|
|
HEADERS = {
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
"X-Identifier": TINANCE2_READER_IDENTIFIER,
|
|
|
|
"X-Access-Key": TINANCE2_READER_ACCESS_KEY
|
|
|
|
}
|
|
|
|
|
2023-10-31 21:55:09 +00:00
|
|
|
# Define a maximum number of retry attempts and a delay between retries
|
2023-10-31 23:11:00 +00:00
|
|
|
MAX_RETRY_ATTEMPTS = 5 # Changed to 5
|
2023-10-31 21:55:09 +00:00
|
|
|
RETRY_DELAY_SECONDS = 10
|
|
|
|
|
2023-10-31 21:09:34 +00:00
|
|
|
def handle_log_msg(prefix, value):
|
2023-10-31 17:54:21 +00:00
|
|
|
print(f"Received LOG_MSG: {value}")
|
|
|
|
|
2023-10-31 21:55:09 +00:00
|
|
|
def send_http_request_with_retry(url, data, headers):
|
|
|
|
retry_count = 0
|
|
|
|
|
|
|
|
while retry_count < MAX_RETRY_ATTEMPTS:
|
|
|
|
try:
|
|
|
|
response = requests.post(url, json=data, headers=headers)
|
|
|
|
if response.status_code == 200:
|
|
|
|
print(f"Sent FULL_CARD_ID: {data['full_card_id']} via HTTP POST successfully")
|
|
|
|
if reader_info.get("mode") == "LATCH":
|
|
|
|
ser.write("unlock".encode('utf-8'))
|
|
|
|
elif reader_info.get("mode") == "TOGGLE":
|
|
|
|
ser.write("toggle".encode('utf-8'))
|
|
|
|
break # Successful request, no need to retry
|
2023-10-31 23:20:04 +00:00
|
|
|
elif response.status_code in [400, 401, 403, 500]:
|
2023-10-31 23:11:00 +00:00
|
|
|
# Don't retry on certain errors
|
|
|
|
print(f"HTTP POST request failed with status code {response.status_code}. Not retrying.")
|
|
|
|
break
|
2023-10-31 21:55:09 +00:00
|
|
|
else:
|
|
|
|
print(f"Failed to send FULL_CARD_ID via HTTP POST. Status code: {response.status_code}")
|
|
|
|
print(response.text)
|
|
|
|
except (RequestException, ConnectionError) as e:
|
|
|
|
print(f"HTTP request failed with exception: {e}")
|
|
|
|
retry_count += 1
|
|
|
|
if retry_count < MAX_RETRY_ATTEMPTS:
|
|
|
|
print(f"Retrying in {RETRY_DELAY_SECONDS} seconds...")
|
|
|
|
time.sleep(RETRY_DELAY_SECONDS)
|
|
|
|
else:
|
|
|
|
print("Max retry attempts reached. Request failed.")
|
|
|
|
break
|
|
|
|
|
2023-10-31 21:43:38 +00:00
|
|
|
def check_valid_card(prefix, value):
|
2023-10-31 17:54:21 +00:00
|
|
|
if value == "0:0":
|
2023-10-31 21:47:31 +00:00
|
|
|
print("Received invalid card ID (0:0), ignoring...")
|
2023-10-31 17:54:21 +00:00
|
|
|
return
|
|
|
|
|
2023-10-31 21:47:31 +00:00
|
|
|
url = f'{API_BASE_URL}check-card-id'
|
|
|
|
data_to_post = {"full_card_id": value}
|
|
|
|
|
2023-10-31 21:55:09 +00:00
|
|
|
send_http_request_with_retry(url, data_to_post, HEADERS)
|
2023-10-31 17:54:21 +00:00
|
|
|
|
2023-10-31 21:43:38 +00:00
|
|
|
def fetch_initial_reader_config():
|
|
|
|
try:
|
2023-10-31 21:47:31 +00:00
|
|
|
url = f'{API_BASE_URL}readerinfo'
|
|
|
|
response = requests.get(url, headers=HEADERS)
|
2023-10-31 21:43:38 +00:00
|
|
|
|
|
|
|
if response.status_code == 200:
|
|
|
|
data = response.json()
|
|
|
|
reader_info["enabled"] = data.get("enabled", False)
|
|
|
|
reader_info["mode"] = data.get("mode")
|
2023-10-31 21:55:09 +00:00
|
|
|
except (RequestException, ConnectionError) as e:
|
2023-10-31 21:43:38 +00:00
|
|
|
print(f"Error fetching initial reader config: {e}")
|
|
|
|
|
2023-10-31 21:09:34 +00:00
|
|
|
def reader_config_check():
|
|
|
|
while True:
|
2023-10-31 22:04:44 +00:00
|
|
|
try:
|
|
|
|
print("Checking HTTP endpoint for new reader config...")
|
|
|
|
url = f'{API_BASE_URL}readerinfo'
|
|
|
|
response = requests.get(url, headers=HEADERS)
|
2023-10-31 21:09:34 +00:00
|
|
|
|
2023-10-31 22:04:44 +00:00
|
|
|
if response.status_code == 200:
|
|
|
|
data = response.json()
|
|
|
|
new_enabled = data.get("enabled", False)
|
|
|
|
new_mode = data.get("mode")
|
|
|
|
|
|
|
|
if new_enabled != reader_info["enabled"]:
|
|
|
|
print("New reader enabled status: ", new_enabled)
|
|
|
|
if new_enabled:
|
|
|
|
print("Enabling reader...")
|
|
|
|
ser.write("enable".encode('utf-8'))
|
|
|
|
else:
|
|
|
|
print("Disabling reader...")
|
|
|
|
ser.write("disable".encode('utf-8'))
|
|
|
|
reader_info["enabled"] = new_enabled
|
|
|
|
|
|
|
|
if new_mode != reader_info["mode"]:
|
|
|
|
print("Reader mode has changed: ", new_mode)
|
|
|
|
if new_mode == "LATCH" and reader_info["mode"] == "TOGGLE":
|
|
|
|
print("Transitioned from TOGGLE to LATCH, sending 'lock' over serial...")
|
|
|
|
ser.write("lock".encode("utf-8"))
|
|
|
|
reader_info["mode"] = new_mode
|
|
|
|
|
|
|
|
if new_mode == "LATCH" and reader_info["mode"] == "TOGGLE":
|
|
|
|
print("Transitioned from LATCH to TOGGLE, sending 'unlock' over serial...")
|
|
|
|
time.sleep(10) # Check every 10 seconds
|
|
|
|
except (RequestException, ConnectionError) as e:
|
|
|
|
print(f"HTTP request failed with exception: {e}")
|
|
|
|
time.sleep(10) # Retry after 10 seconds
|
2023-10-31 21:43:38 +00:00
|
|
|
|
|
|
|
def serial_router():
|
2023-10-31 21:09:34 +00:00
|
|
|
while True:
|
|
|
|
data = ser.readline()
|
2023-10-31 17:54:21 +00:00
|
|
|
try:
|
|
|
|
data = data.decode('utf-8')
|
2023-11-01 16:45:12 +00:00
|
|
|
try:
|
|
|
|
if '=' in data:
|
|
|
|
prefix, value = data.split('=')
|
|
|
|
prefix = prefix.strip()
|
|
|
|
value = value.strip()
|
|
|
|
|
|
|
|
actions = {
|
|
|
|
"LOG_MSG": handle_log_msg,
|
|
|
|
"FULL_CARD_ID": check_valid_card,
|
|
|
|
"DOOR_DISABLED_STATUS": handle_log_msg,
|
|
|
|
"DOOR_LOCK_STATUS": handle_log_msg
|
|
|
|
}
|
|
|
|
|
|
|
|
if prefix in actions:
|
|
|
|
actions[prefix](prefix, value)
|
|
|
|
else:
|
|
|
|
print(f"Unknown prefix: {prefix}")
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
hex_data = binascii.hexlify(data).decode('utf-8')
|
|
|
|
print(f"Received non-UTF-8 data: {hex_data}")
|
|
|
|
except:
|
|
|
|
print("Error decoding serial data")
|
2023-10-31 21:09:34 +00:00
|
|
|
|
2023-10-31 22:04:44 +00:00
|
|
|
def start_thread(thread_function):
|
|
|
|
thread = threading.Thread(target=thread_function)
|
|
|
|
thread.daemon = True
|
|
|
|
thread.start()
|
|
|
|
return thread
|
|
|
|
|
2023-10-31 21:09:34 +00:00
|
|
|
if __name__ == "__main__":
|
2023-10-31 21:47:31 +00:00
|
|
|
ser = serial.Serial(SERIAL_PORT, BAUD_RATE)
|
2023-10-31 22:04:44 +00:00
|
|
|
|
2023-10-31 21:43:38 +00:00
|
|
|
# Fetch the initial reader configuration
|
|
|
|
fetch_initial_reader_config()
|
|
|
|
|
2023-10-31 22:04:44 +00:00
|
|
|
# Create and start the threads
|
|
|
|
threads = [start_thread(serial_router), start_thread(reader_config_check)]
|
2023-10-31 21:09:34 +00:00
|
|
|
|
2023-10-31 22:04:44 +00:00
|
|
|
# Wait for threads to finish (which is never in this case since they run indefinitely)
|
|
|
|
for thread in threads:
|
|
|
|
thread.join()
|