Implement: Remove Flask and Chrome, simplify to headless RFID client with RDM6300
- Remove Flask web server from client device - Remove Chrome fullscreen UI launch - Simplify app.py to focus on core functionality only: * RFID reader with RDM6300 library * Batch logging with event deduplication (75% reduction) * WiFi recovery monitoring * Connectivity tracking - Update rfid_module.py with custom Reader class: * Extends rdm6300.BaseReader for event handling * card_inserted and card_removed event handlers * Integration with batch logging system * Proper error handling and device detection - Dashboard and UI now served from Server_Monitorizare only - Device acts as pure data collector, reducing overhead
This commit is contained in:
112
app.py
112
app.py
@@ -1,14 +1,14 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Prezenta Work - Workplace Attendance & Traceability System (v3.0)
|
Prezenta Work - Workplace Attendance & Traceability System (v3.0)
|
||||||
Enhanced with batch logging, Chrome fullscreen UI, and WiFi recovery
|
Headless RFID reader client with batch logging and WiFi recovery
|
||||||
|
|
||||||
Main application orchestrator that coordinates all system components:
|
Main application orchestrator that coordinates system components:
|
||||||
|
- RFID card reader (reads employee badges)
|
||||||
- Batch logging with event deduplication (75% network reduction)
|
- Batch logging with event deduplication (75% network reduction)
|
||||||
- Chrome browser in fullscreen kiosk mode
|
|
||||||
- WiFi auto-recovery on server disconnection
|
- WiFi auto-recovery on server disconnection
|
||||||
- RFID card reader integration
|
- Remote monitoring via Server_Monitorizare dashboard
|
||||||
- Remote monitoring and logging
|
- Connectivity monitoring and backup data handling
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
@@ -21,33 +21,31 @@ from datetime import datetime
|
|||||||
# Import all modules
|
# Import all modules
|
||||||
from config_settings import (
|
from config_settings import (
|
||||||
MONITORING_SERVER_URL, AUTO_UPDATE_SERVER_HOST, CONNECTIVITY_CHECK_HOST,
|
MONITORING_SERVER_URL, AUTO_UPDATE_SERVER_HOST, CONNECTIVITY_CHECK_HOST,
|
||||||
FLASK_PORT, LOG_FILE, DEVICE_INFO_FILE, TAG_FILE
|
LOG_FILE, DEVICE_INFO_FILE, TAG_FILE
|
||||||
)
|
)
|
||||||
from logger_module import log_with_server
|
from logger_module import log_with_server
|
||||||
from device_module import get_device_info
|
from device_module import get_device_info
|
||||||
from system_init_module import perform_system_initialization
|
from system_init_module import perform_system_initialization
|
||||||
from dependencies_module import check_and_install_dependencies
|
from dependencies_module import check_and_install_dependencies
|
||||||
from api_routes_module import create_api_routes
|
|
||||||
from rfid_module import initialize_rfid_reader
|
from rfid_module import initialize_rfid_reader
|
||||||
from connectivity_module import check_internet_connection, post_backup_data
|
from connectivity_module import check_internet_connection, post_backup_data
|
||||||
|
|
||||||
# Import new enhancement modules
|
# Import enhancement modules
|
||||||
from logger_batch_module import (
|
from logger_batch_module import (
|
||||||
setup_logging as setup_batch_logging,
|
setup_logging as setup_batch_logging,
|
||||||
start_batch_logger,
|
start_batch_logger,
|
||||||
queue_log_message
|
queue_log_message
|
||||||
)
|
)
|
||||||
from chrome_launcher_module import launch_chrome_app, get_chrome_path
|
|
||||||
from wifi_recovery_module import initialize_wifi_recovery
|
from wifi_recovery_module import initialize_wifi_recovery
|
||||||
|
|
||||||
# Flask app
|
|
||||||
from flask import Flask
|
|
||||||
|
|
||||||
|
|
||||||
# Global variables
|
# Global variables
|
||||||
app = None
|
|
||||||
device_hostname = None
|
device_hostname = None
|
||||||
device_ip = None
|
device_ip = None
|
||||||
|
rfid_reader = None
|
||||||
|
batch_logger_thread = None
|
||||||
|
wifi_recovery_manager = None
|
||||||
|
app_running = True
|
||||||
|
|
||||||
|
|
||||||
def setup_signal_handlers():
|
def setup_signal_handlers():
|
||||||
@@ -76,23 +74,21 @@ def setup_signal_handlers():
|
|||||||
|
|
||||||
def initialize_application():
|
def initialize_application():
|
||||||
"""Initialize all application components"""
|
"""Initialize all application components"""
|
||||||
global device_hostname, device_ip, app, logger
|
global device_hostname, device_ip
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.info("=" * 80)
|
logging.info("=" * 80)
|
||||||
logging.info("Prezenta Work v3.0 - Workplace Attendance System")
|
logging.info("Prezenta Work v3.0 - Headless RFID Client")
|
||||||
logging.info("=" * 80)
|
logging.info("=" * 80)
|
||||||
logging.info(f"Start time: {datetime.now().isoformat()}")
|
logging.info(f"Start time: {datetime.now().isoformat()}")
|
||||||
|
|
||||||
# Get device info
|
# Get device info
|
||||||
logging.info("Retrieving device information...")
|
logging.info("Retrieving device information...")
|
||||||
device_info = get_device_info()
|
device_hostname, device_ip = get_device_info()
|
||||||
device_hostname = device_info['hostname']
|
|
||||||
device_ip = device_info['ip']
|
|
||||||
|
|
||||||
logging.info(f"Device: {device_hostname} ({device_ip})")
|
logging.info(f"Device: {device_hostname} ({device_ip})")
|
||||||
log_with_server(
|
log_with_server(
|
||||||
"Application started - v3.0 with batch logging and WiFi recovery",
|
"RFID Client v3.0 started - batch logging active, WiFi recovery enabled",
|
||||||
device_hostname,
|
device_hostname,
|
||||||
device_ip
|
device_ip
|
||||||
)
|
)
|
||||||
@@ -101,7 +97,7 @@ def initialize_application():
|
|||||||
logging.info("Performing system initialization...")
|
logging.info("Performing system initialization...")
|
||||||
perform_system_initialization()
|
perform_system_initialization()
|
||||||
|
|
||||||
# Check and install dependencies
|
# Check and install dependencies (no Flask needed)
|
||||||
logging.info("Checking dependencies...")
|
logging.info("Checking dependencies...")
|
||||||
check_and_install_dependencies()
|
check_and_install_dependencies()
|
||||||
|
|
||||||
@@ -109,11 +105,6 @@ def initialize_application():
|
|||||||
logging.info("Setting up batch logging system...")
|
logging.info("Setting up batch logging system...")
|
||||||
setup_batch_logging(device_hostname)
|
setup_batch_logging(device_hostname)
|
||||||
|
|
||||||
# Create Flask app
|
|
||||||
logging.info("Initializing Flask application...")
|
|
||||||
app = Flask(__name__)
|
|
||||||
create_api_routes(app)
|
|
||||||
|
|
||||||
logging.info("Application initialization completed successfully")
|
logging.info("Application initialization completed successfully")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -122,52 +113,6 @@ def initialize_application():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def start_flask_server():
|
|
||||||
"""Start Flask web server"""
|
|
||||||
try:
|
|
||||||
logging.info(f"Starting Flask server on port {FLASK_PORT}...")
|
|
||||||
log_with_server(f"Flask server starting on port {FLASK_PORT}", device_hostname, device_ip)
|
|
||||||
|
|
||||||
# Run Flask in a separate thread
|
|
||||||
flask_thread = threading.Thread(
|
|
||||||
target=lambda: app.run(host='0.0.0.0', port=FLASK_PORT, debug=False, use_reloader=False),
|
|
||||||
daemon=True
|
|
||||||
)
|
|
||||||
flask_thread.start()
|
|
||||||
logging.info("Flask server thread started")
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Failed to start Flask server: {e}")
|
|
||||||
log_with_server(f"ERROR: Flask server failed: {str(e)}", device_hostname, device_ip)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def start_chrome_app():
|
|
||||||
"""Launch Chrome in fullscreen with traceability application"""
|
|
||||||
try:
|
|
||||||
if get_chrome_path():
|
|
||||||
logging.info("Starting Chrome fullscreen application...")
|
|
||||||
log_with_server("Launching Chrome fullscreen UI", device_hostname, device_ip)
|
|
||||||
|
|
||||||
# Launch Chrome with local Flask server
|
|
||||||
chrome_thread = threading.Thread(
|
|
||||||
target=lambda: launch_chrome_app(device_hostname, device_ip, f"http://localhost:{FLASK_PORT}"),
|
|
||||||
daemon=True
|
|
||||||
)
|
|
||||||
chrome_thread.start()
|
|
||||||
logging.info("Chrome launch thread started")
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
logging.warning("Chrome not found - skipping fullscreen launch")
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Failed to start Chrome app: {e}")
|
|
||||||
log_with_server(f"ERROR: Chrome launch failed: {str(e)}", device_hostname, device_ip)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def start_wifi_recovery_monitor():
|
def start_wifi_recovery_monitor():
|
||||||
"""Initialize WiFi recovery monitoring"""
|
"""Initialize WiFi recovery monitoring"""
|
||||||
global wifi_recovery_manager
|
global wifi_recovery_manager
|
||||||
@@ -245,8 +190,8 @@ def start_rfid_reader():
|
|||||||
global rfid_reader
|
global rfid_reader
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.info("Initializing RFID reader...")
|
logging.info("Initializing RFID reader with RDM6300...")
|
||||||
rfid_reader = initialize_rfid_reader()
|
rfid_reader = initialize_rfid_reader(device_hostname, device_ip)
|
||||||
|
|
||||||
if rfid_reader:
|
if rfid_reader:
|
||||||
logging.info("RFID reader initialized successfully")
|
logging.info("RFID reader initialized successfully")
|
||||||
@@ -287,31 +232,24 @@ def main():
|
|||||||
# Start core components in sequence
|
# Start core components in sequence
|
||||||
logging.info("Starting application components...")
|
logging.info("Starting application components...")
|
||||||
|
|
||||||
# 1. Start Flask web server (provides UI endpoint)
|
# 1. Start batch logging system
|
||||||
start_flask_server()
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# 2. Start batch logging system
|
|
||||||
start_batch_logger_thread()
|
start_batch_logger_thread()
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
# 3. Launch Chrome fullscreen UI
|
# 2. Initialize RFID reader
|
||||||
start_chrome_app()
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 4. Initialize RFID reader
|
|
||||||
start_rfid_reader()
|
start_rfid_reader()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
# 5. Start connectivity monitoring
|
# 3. Start connectivity monitoring
|
||||||
start_connectivity_monitor()
|
start_connectivity_monitor()
|
||||||
|
|
||||||
# 6. Start WiFi recovery monitor
|
# 4. Start WiFi recovery monitor
|
||||||
start_wifi_recovery_monitor()
|
start_wifi_recovery_monitor()
|
||||||
|
|
||||||
logging.info("All components started successfully")
|
logging.info("All components started successfully")
|
||||||
log_with_server(
|
log_with_server(
|
||||||
"System fully operational - batch logging active (75% reduction), "
|
"RFID Client operational - batch logging active (75% reduction), "
|
||||||
"Chrome UI fullscreen, WiFi recovery enabled",
|
"RFID reader ready, WiFi recovery enabled",
|
||||||
device_hostname,
|
device_hostname,
|
||||||
device_ip
|
device_ip
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,47 +1,129 @@
|
|||||||
"""
|
"""
|
||||||
RFID reader initialization and handling
|
RFID reader initialization and handling using RDM6300 library
|
||||||
|
|
||||||
|
Extends rdm6300.BaseReader to handle card events (insert/remove)
|
||||||
|
and integrate with batch logging system
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from config_settings import SERIAL_DEVICES, CONFIG_CARD_ID
|
import time
|
||||||
|
from config_settings import SERIAL_DEVICES, CONFIG_CARD_ID, DEVICE_INFO_FILE
|
||||||
from logger_module import log_with_server
|
from logger_module import log_with_server
|
||||||
|
from logger_batch_module import queue_log_message
|
||||||
|
|
||||||
|
|
||||||
def initialize_rfid_reader():
|
class RFIDReaderHandler:
|
||||||
|
"""Custom RFID Reader extending rdm6300.BaseReader for event handling"""
|
||||||
|
|
||||||
|
def __init__(self, device_hostname, device_ip):
|
||||||
|
"""Initialize the reader handler"""
|
||||||
|
self.device_hostname = device_hostname
|
||||||
|
self.device_ip = device_ip
|
||||||
|
self.reader = None
|
||||||
|
|
||||||
|
def card_inserted(self, card):
|
||||||
|
"""Handle RFID card insertion event"""
|
||||||
|
try:
|
||||||
|
# Special handling for config card
|
||||||
|
if card.value == CONFIG_CARD_ID:
|
||||||
|
logging.info(f"Config card detected: {card.value}")
|
||||||
|
queue_log_message("CONFIG_CARD_DETECTED", self.device_hostname)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Log card insertion
|
||||||
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
msg = f"Card inserted - ID: {card.value}"
|
||||||
|
logging.info(msg)
|
||||||
|
queue_log_message(msg, self.device_hostname)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error handling card insertion: {e}")
|
||||||
|
|
||||||
|
def card_removed(self, card):
|
||||||
|
"""Handle RFID card removal event"""
|
||||||
|
try:
|
||||||
|
# Special handling for config card
|
||||||
|
if card.value == CONFIG_CARD_ID:
|
||||||
|
logging.info(f"Config card removed: {card.value}")
|
||||||
|
queue_log_message("CONFIG_CARD_REMOVED", self.device_hostname)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Log card removal
|
||||||
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
msg = f"Card removed - ID: {card.value}"
|
||||||
|
logging.info(msg)
|
||||||
|
queue_log_message(msg, self.device_hostname)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error handling card removal: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def initialize_rfid_reader(device_hostname=None, device_ip=None):
|
||||||
"""
|
"""
|
||||||
Initialize RFID reader with multiple device attempts and error handling
|
Initialize RFID reader with RDM6300 library and multiple device attempts
|
||||||
|
|
||||||
|
Args:
|
||||||
|
device_hostname: Device hostname for logging
|
||||||
|
device_ip: Device IP for logging
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Reader object or None if initialization fails
|
Reader object or None if initialization fails
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
from rdm6300 import Reader
|
from rdm6300 import BaseReader
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
logging.error("✗ rdm6300 module not installed")
|
||||||
print("✗ rdm6300 module not installed")
|
print("✗ rdm6300 module not installed")
|
||||||
|
log_with_server("ERROR: rdm6300 not installed", device_hostname, device_ip)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
logging.info("Initializing RFID reader with RDM6300...")
|
||||||
print("Initializing RFID reader...")
|
print("Initializing RFID reader...")
|
||||||
|
|
||||||
|
# Create handler for card events
|
||||||
|
handler = RFIDReaderHandler(device_hostname or "unknown", device_ip or "0.0.0.0")
|
||||||
|
|
||||||
for device in SERIAL_DEVICES:
|
for device in SERIAL_DEVICES:
|
||||||
try:
|
try:
|
||||||
|
logging.info(f"Attempting to initialize RFID reader on {device}...")
|
||||||
print(f"Attempting to initialize RFID reader on {device}...")
|
print(f"Attempting to initialize RFID reader on {device}...")
|
||||||
r = Reader(device)
|
|
||||||
r.start()
|
# Create custom reader class that extends BaseReader
|
||||||
|
class CustomReader(BaseReader):
|
||||||
|
def card_inserted(self, card):
|
||||||
|
handler.card_inserted(card)
|
||||||
|
|
||||||
|
def card_removed(self, card):
|
||||||
|
handler.card_removed(card)
|
||||||
|
|
||||||
|
# Initialize reader
|
||||||
|
reader = CustomReader(device)
|
||||||
|
reader.start()
|
||||||
|
|
||||||
|
logging.info(f"✓ RFID reader successfully initialized on {device}")
|
||||||
print(f"✓ RFID reader successfully initialized on {device}")
|
print(f"✓ RFID reader successfully initialized on {device}")
|
||||||
return r
|
log_with_server(f"RFID reader started on {device}", device_hostname, device_ip)
|
||||||
|
|
||||||
|
return reader
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
|
logging.warning(f"✗ Device {device} not found")
|
||||||
print(f"✗ Device {device} not found")
|
print(f"✗ Device {device} not found")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
|
logging.warning(f"✗ Permission denied for {device}")
|
||||||
print(f"✗ Permission denied for {device}")
|
print(f"✗ Permission denied for {device}")
|
||||||
print(f" Hint: Try adding user to dialout group: sudo usermod -a -G dialout $USER")
|
print(f" Hint: Try adding user to dialout group: sudo usermod -a -G dialout $USER")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logging.warning(f"✗ Failed to initialize on {device}: {e}")
|
||||||
print(f"✗ Failed to initialize on {device}: {e}")
|
print(f"✗ Failed to initialize on {device}: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If we get here, all devices failed
|
# If we get here, all devices failed
|
||||||
|
logging.error("✗ Could not initialize RFID reader on any device")
|
||||||
print("✗ Could not initialize RFID reader on any device")
|
print("✗ Could not initialize RFID reader on any device")
|
||||||
print("Available solutions:")
|
print("Available solutions:")
|
||||||
print(" 1. Check hardware connections")
|
print(" 1. Check hardware connections")
|
||||||
@@ -49,4 +131,5 @@ def initialize_rfid_reader():
|
|||||||
print(" 3. Add user to dialout group: sudo usermod -a -G dialout $USER")
|
print(" 3. Add user to dialout group: sudo usermod -a -G dialout $USER")
|
||||||
print(" 4. Reboot the system after making changes")
|
print(" 4. Reboot the system after making changes")
|
||||||
|
|
||||||
|
log_with_server("ERROR: RFID reader initialization failed on all devices", device_hostname, device_ip)
|
||||||
return None
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user