diff --git a/app.py b/app.py index 130dd0c..c4245f9 100644 --- a/app.py +++ b/app.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 """ 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) -- Chrome browser in fullscreen kiosk mode - WiFi auto-recovery on server disconnection -- RFID card reader integration -- Remote monitoring and logging +- Remote monitoring via Server_Monitorizare dashboard +- Connectivity monitoring and backup data handling """ import signal @@ -21,33 +21,31 @@ from datetime import datetime # Import all modules from config_settings import ( 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 device_module import get_device_info from system_init_module import perform_system_initialization from dependencies_module import check_and_install_dependencies -from api_routes_module import create_api_routes from rfid_module import initialize_rfid_reader from connectivity_module import check_internet_connection, post_backup_data -# Import new enhancement modules +# Import enhancement modules from logger_batch_module import ( setup_logging as setup_batch_logging, start_batch_logger, queue_log_message ) -from chrome_launcher_module import launch_chrome_app, get_chrome_path from wifi_recovery_module import initialize_wifi_recovery -# Flask app -from flask import Flask - # Global variables -app = None device_hostname = None device_ip = None +rfid_reader = None +batch_logger_thread = None +wifi_recovery_manager = None +app_running = True def setup_signal_handlers(): @@ -76,23 +74,21 @@ def setup_signal_handlers(): def initialize_application(): """Initialize all application components""" - global device_hostname, device_ip, app, logger + global device_hostname, device_ip try: 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(f"Start time: {datetime.now().isoformat()}") # Get device info logging.info("Retrieving device information...") - device_info = get_device_info() - device_hostname = device_info['hostname'] - device_ip = device_info['ip'] + device_hostname, device_ip = get_device_info() logging.info(f"Device: {device_hostname} ({device_ip})") 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_ip ) @@ -101,7 +97,7 @@ def initialize_application(): logging.info("Performing system initialization...") perform_system_initialization() - # Check and install dependencies + # Check and install dependencies (no Flask needed) logging.info("Checking dependencies...") check_and_install_dependencies() @@ -109,11 +105,6 @@ def initialize_application(): logging.info("Setting up batch logging system...") 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") return True @@ -122,52 +113,6 @@ def initialize_application(): 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(): """Initialize WiFi recovery monitoring""" global wifi_recovery_manager @@ -245,8 +190,8 @@ def start_rfid_reader(): global rfid_reader try: - logging.info("Initializing RFID reader...") - rfid_reader = initialize_rfid_reader() + logging.info("Initializing RFID reader with RDM6300...") + rfid_reader = initialize_rfid_reader(device_hostname, device_ip) if rfid_reader: logging.info("RFID reader initialized successfully") @@ -287,31 +232,24 @@ def main(): # Start core components in sequence logging.info("Starting application components...") - # 1. Start Flask web server (provides UI endpoint) - start_flask_server() - time.sleep(1) - - # 2. Start batch logging system + # 1. Start batch logging system start_batch_logger_thread() time.sleep(0.5) - # 3. Launch Chrome fullscreen UI - start_chrome_app() - time.sleep(2) - - # 4. Initialize RFID reader + # 2. Initialize RFID reader start_rfid_reader() + time.sleep(1) - # 5. Start connectivity monitoring + # 3. Start connectivity monitoring start_connectivity_monitor() - # 6. Start WiFi recovery monitor + # 4. Start WiFi recovery monitor start_wifi_recovery_monitor() logging.info("All components started successfully") log_with_server( - "System fully operational - batch logging active (75% reduction), " - "Chrome UI fullscreen, WiFi recovery enabled", + "RFID Client operational - batch logging active (75% reduction), " + "RFID reader ready, WiFi recovery enabled", device_hostname, device_ip ) diff --git a/rfid_module.py b/rfid_module.py index 3dbb143..cbf2db2 100644 --- a/rfid_module.py +++ b/rfid_module.py @@ -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 -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_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: Reader object or None if initialization fails """ try: - from rdm6300 import Reader + from rdm6300 import BaseReader except ImportError: + logging.error("✗ rdm6300 module not installed") print("✗ rdm6300 module not installed") + log_with_server("ERROR: rdm6300 not installed", device_hostname, device_ip) return None + logging.info("Initializing RFID reader with RDM6300...") 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: try: + logging.info(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}") - return r + log_with_server(f"RFID reader started on {device}", device_hostname, device_ip) + + return reader except FileNotFoundError: + logging.warning(f"✗ Device {device} not found") print(f"✗ Device {device} not found") continue + except PermissionError: + logging.warning(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") continue + except Exception as e: + logging.warning(f"✗ Failed to initialize on {device}: {e}") print(f"✗ Failed to initialize on {device}: {e}") continue # 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("Available solutions:") 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(" 4. Reboot the system after making changes") + log_with_server("ERROR: RFID reader initialization failed on all devices", device_hostname, device_ip) return None