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
.envfile 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 -ysudo apt autoremove -y,sudo apt autocleansudo reboot,sudo shutdown -h nowdf -h,free -m,uptime,systemctl statussudo 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:
- Get local app version (from first line:
#App version X.X) - Connect to update server via SSH
- Compare versions
- 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
- Create a new module:
my_feature_module.py - Implement your logic
- Update
api_routes_module.pyto register the route - 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:
- Try-except blocks for external operations
- Logging of all errors via logger_module
- Graceful degradation when components fail
- 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_HOSTin 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
- Test the new modular app:
python3 app_modular.py - Verify all features work: Test
/status,/execute_command,/auto_updateendpoints - Update documentation for your team
- Gradually migrate from old app to new app
- 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)