Files
prezenta_work/oldcode/MODULAR_ARCHITECTURE.md

12 KiB

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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

# 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:

# 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:

# 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:

MONITORING_SERVER_HOST=new-server.com python3 app_modular.py

Example: Modify Allowed Commands

Edit config_settings.py:

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

sudo setcap cap_net_bind_service=ep $(which python3)

RFID Reader Not Found

# 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:

[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:

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)