# Prezenta Work - Modular Architecture Guide ## Overview The application has been refactored from a monolithic `app.py` (1334 lines) into a modular structure with separation of concerns. Each module handles a specific responsibility. --- ## Module Structure ### Core Configuration **File:** `config_settings.py` - **Purpose:** Centralized configuration management - **Responsibilities:** - Server addresses and credentials - File paths and directories - Flask configuration - Hardware settings - Logging configuration - Allowed commands list - Environment variable loading from `.env` **Key Features:** - All settings in one place - Environment variable support (can override defaults) - Automatic directory creation - `.env` file support for sensitive data --- ### Logging Module **File:** `logger_module.py` - **Purpose:** Unified logging system - **Responsibilities:** - Local file logging - Remote server notifications - Log rotation (10-day retention) - Device/table name management **Key Functions:** ```python setup_logging() # Configure logger log_with_server() # Log locally + send to server send_log_to_server() # Send to monitoring server read_masa_name() # Get table/room name delete_old_logs() # Cleanup old logs ``` --- ### Device Module **File:** `device_module.py` - **Purpose:** Device information management - **Responsibilities:** - Get hostname and IP address - File-based fallback for device info - Handle network resolution errors **Key Functions:** ```python get_device_info() # Returns (hostname, device_ip) ``` --- ### System Initialization **File:** `system_init_module.py` - **Purpose:** First-run setup and hardware validation - **Responsibilities:** - System requirements checking - Port capability setup (port 80) - Hardware interface detection (UART/Serial) - GPIO permission setup - Network connectivity check - Required file creation **Key Functions:** ```python perform_system_initialization() # Main initialization check_system_requirements() check_port_capabilities() check_hardware_interfaces() initialize_gpio_permissions() check_network_connectivity() create_required_files() ``` --- ### Dependencies Management **File:** `dependencies_module.py` - **Purpose:** Package installation and verification - **Responsibilities:** - Wheel file installation - Pip package installation - Apt system package installation - Dependency verification **Key Functions:** ```python check_and_install_dependencies() # Install missing packages verify_dependencies() # Verify all packages available install_package_from_wheel() # Install from wheel file ``` --- ### Commands Execution **File:** `commands_module.py` - **Purpose:** Secure command execution with restrictions - **Responsibilities:** - Command allowlist enforcement - Execution with timeout - Logging command results - Error handling and reporting **Key Functions:** ```python execute_system_command(command, hostname, device_ip) ``` **Allowed Commands:** - `sudo apt update`, `sudo apt upgrade -y` - `sudo apt autoremove -y`, `sudo apt autoclean` - `sudo reboot`, `sudo shutdown -h now` - `df -h`, `free -m`, `uptime`, `systemctl status` - `sudo systemctl restart networking/ssh` --- ### Auto-Update Module **File:** `autoupdate_module.py` - **Purpose:** Remote application updates - **Responsibilities:** - Version checking - Remote file downloading - Backup creation - Update verification - Device restart scheduling **Key Functions:** ```python perform_auto_update() # Main update process get_app_version() # Extract version from app check_remote_version() # Check server version ``` **Process:** 1. Get local app version (from first line: `#App version X.X`) 2. Connect to update server via SSH 3. Compare versions 4. If update available: - Create backup - Download new files - Schedule device restart --- ### Connectivity Module **File:** `connectivity_module.py` - **Purpose:** Network monitoring and backup data handling - **Responsibilities:** - Periodic connectivity checks - Fallback data posting - Harting server integration **Key Functions:** ```python check_internet_connection() # Periodic connectivity monitoring post_backup_data() # Send queued data to Harting server ``` **Features:** - Checks internet every 45 minutes - Posts queued URLs from `tag.txt` - Retry logic for failed posts - Automatic cleanup of successful posts --- ### API Routes Module **File:** `api_routes_module.py` - **Purpose:** Flask API endpoints - **Responsibilities:** - Route registration - Request handling - Response formatting **Key Endpoints:** ``` POST /execute_command - Execute allowed system commands GET /status - Get device status information POST /auto_update - Trigger application update ``` **Key Functions:** ```python create_api_routes(app, hostname, device_ip, local_app_path, local_repo_path) ``` --- ### RFID Module **File:** `rfid_module.py` - **Purpose:** RFID reader initialization - **Responsibilities:** - Reader initialization with multiple device attempts - Error handling and troubleshooting **Key Functions:** ```python initialize_rfid_reader() # Initialize RFID reader ``` **Supported Devices:** - `/dev/ttyS0` - Raspberry Pi default UART - `/dev/ttyAMA0` - Alternative Pi UART - `/dev/ttyUSB0` - USB serial adapter - `/dev/ttyACM0` - USB CDC ACM device --- ### Main Application **File:** `app_modular.py` - **Purpose:** Application orchestration and startup - **Responsibilities:** - Initialize all modules in sequence - Start Flask server - Start connectivity monitoring - Start RFID reader - Handle errors and shutdown **Key Functions:** ```python main() # Application entry point initialize_application() # Setup phase start_flask_server() # Start HTTP API start_connectivity_monitor() # Background monitoring start_rfid_reader() # RFID initialization ``` --- ## Usage ### Running the Application ```bash # Run with default configuration python3 app_modular.py # Run with environment variables MONITORING_SERVER_HOST=192.168.1.100 FLASK_PORT=8080 python3 app_modular.py ``` ### Environment Variables Create a `.env` file in the application directory: ```env # Server Configuration MONITORING_SERVER_HOST=rpi-ansible MONITORING_SERVER_PORT=80 AUTO_UPDATE_SERVER_HOST=rpi-ansible AUTO_UPDATE_SERVER_USER=pi AUTO_UPDATE_SERVER_PASSWORD=your_password CONNECTIVITY_CHECK_HOST=10.76.140.17 # Flask Configuration FLASK_PORT=80 ``` ### Configuration Files #### Device Configuration - **`./data/idmasa.txt`** - Table/room name (used in all logs) - **`./data/device_info.txt`** - Cached hostname & IP (fallback) - **`./data/tag.txt`** - Harting server URLs for backup posting - **`./data/log.txt`** - Application logs (auto-rotated at 10 days) --- ## Dependency Tree ``` app_modular.py (Main) ├── config_settings.py (Configuration) ├── dependencies_module.py (Package Management) ├── system_init_module.py (Initialization) │ └── config_settings.py ├── device_module.py (Device Info) │ └── config_settings.py ├── logger_module.py (Logging) │ ├── config_settings.py │ └── External: requests ├── connectivity_module.py (Network) │ ├── config_settings.py │ ├── logger_module.py │ └── External: requests ├── commands_module.py (Command Execution) │ ├── config_settings.py │ └── logger_module.py ├── autoupdate_module.py (Updates) │ ├── config_settings.py │ └── logger_module.py ├── api_routes_module.py (API) │ ├── commands_module.py │ ├── autoupdate_module.py │ ├── logger_module.py │ └── External: Flask └── rfid_module.py (RFID) ├── config_settings.py └── External: rdm6300 ``` --- ## Migration from Old App The old monolithic `app.py` has been preserved. To use the new modular version: ```bash # The old app python3 app.py # The new modular app python3 app_modular.py ``` Both versions can coexist during testing and transition period. --- ## Benefits of Modular Architecture ### ✅ Maintainability - Each module has a single responsibility - Easy to locate and fix bugs - Clear code organization ### ✅ Testability - Modules can be unit tested independently - Easier to mock dependencies - Cleaner test structure ### ✅ Reusability - Modules can be imported and used elsewhere - Configuration module can be shared with other apps - Logger and connectivity modules are standalone ### ✅ Scalability - Easy to add new features in separate modules - New endpoints can be added without modifying core code - Configuration management is centralized ### ✅ Readability - Smaller files are easier to understand - Clear module naming reflects responsibility - Better code organization ### ✅ Flexibility - Easy to swap implementations - Configuration can be externalized - Environment-specific settings via `.env` --- ## Adding New Features ### Example: Add a New API Endpoint 1. Create a new module: `my_feature_module.py` 2. Implement your logic 3. Update `api_routes_module.py` to register the route 4. Test independently ### Example: Change Server Address Edit `config_settings.py` or set environment variable: ```bash MONITORING_SERVER_HOST=new-server.com python3 app_modular.py ``` ### Example: Modify Allowed Commands Edit `config_settings.py`: ```python ALLOWED_COMMANDS = [ # ... existing commands ... "my_custom_command arg1 arg2" ] ``` --- ## Error Handling Each module follows consistent error handling: 1. **Try-except blocks** for external operations 2. **Logging** of all errors via logger_module 3. **Graceful degradation** when components fail 4. **Informative messages** for debugging --- ## Performance Considerations - **Modular imports** only load necessary dependencies - **Lazy loading** of Flask only when available - **Daemon threads** for background tasks - **Subprocess timeouts** prevent hanging operations --- ## Troubleshooting ### Port 80 Permission Denied ```bash sudo setcap cap_net_bind_service=ep $(which python3) ``` ### RFID Reader Not Found ```bash # Add user to dialout group sudo usermod -a -G dialout $USER sudo reboot ``` ### Cannot Connect to Server - Check `MONITORING_SERVER_HOST` in config_settings.py - Verify network connectivity with `ping 8.8.8.8` - Check firewall rules ### Logs Not Sending - Verify server endpoint: `http://MONITORING_SERVER_HOST:80/logs` - Check network connectivity monitor is running - Review log files for error messages --- ## File Summary | File | Lines | Purpose | |------|-------|---------| | `app_modular.py` | ~200 | Application entry point & orchestration | | `config_settings.py` | ~200 | Configuration management | | `logger_module.py` | ~150 | Logging & notifications | | `device_module.py` | ~100 | Device information | | `system_init_module.py` | ~300 | System initialization | | `dependencies_module.py` | ~150 | Package management | | `commands_module.py` | ~80 | Command execution | | `autoupdate_module.py` | ~200 | Auto-update functionality | | `connectivity_module.py` | ~120 | Network monitoring | | `api_routes_module.py` | ~150 | Flask routes | | `rfid_module.py` | ~80 | RFID initialization | | **Total** | **~1530** | **Organized & maintainable** | --- ## Next Steps 1. **Test the new modular app**: `python3 app_modular.py` 2. **Verify all features work**: Test `/status`, `/execute_command`, `/auto_update` endpoints 3. **Update documentation** for your team 4. **Gradually migrate** from old app to new app 5. **Consider systemd service** for automatic startup (see below) --- ## Optional: Systemd Service Create `/etc/systemd/system/prezenta-work.service`: ```ini [Unit] Description=Prezenta Work Attendance System After=network.target [Service] Type=simple User=pi WorkingDirectory=/srv/prezenta_work ExecStart=/usr/bin/python3 /srv/prezenta_work/app_modular.py Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target ``` Then: ```bash sudo systemctl daemon-reload sudo systemctl enable prezenta-work sudo systemctl start prezenta-work sudo systemctl status prezenta-work ``` --- ## Questions or Issues? Refer to individual module documentation or check logs at: - **Application logs:** `./data/log.txt` - **System logs:** `journalctl -u prezenta-work` (if using systemd)