254 lines
8.8 KiB
Python
254 lines
8.8 KiB
Python
"""
|
|
System initialization and hardware checks
|
|
Handles first-run setup and hardware validation
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import stat
|
|
import pwd
|
|
import grp
|
|
from config_settings import SERIAL_DEVICES, GPIO_DEVICES
|
|
|
|
|
|
def check_system_requirements():
|
|
"""Check basic system requirements"""
|
|
print("Checking system requirements...")
|
|
|
|
try:
|
|
# Check if running on supported OS
|
|
if sys.platform not in ['linux', 'linux2']:
|
|
print("⚠ Warning: This application is designed for Linux systems")
|
|
return False
|
|
|
|
# Check Python version
|
|
if sys.version_info < (3, 7):
|
|
print("✗ Python 3.7+ required")
|
|
return False
|
|
|
|
print(f"✓ Python {sys.version_info.major}.{sys.version_info.minor} detected")
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Error checking system requirements: {e}")
|
|
return False
|
|
|
|
|
|
def check_port_capabilities():
|
|
"""Check if the application can bind to port 80"""
|
|
print("Checking port 80 capabilities...")
|
|
|
|
try:
|
|
# Check if we're running as root
|
|
if os.geteuid() == 0:
|
|
print("✓ Running as root - port 80 access available")
|
|
return True
|
|
|
|
# Check if capabilities are set
|
|
python_path = sys.executable
|
|
result = subprocess.run(['getcap', python_path], capture_output=True, text=True)
|
|
|
|
if 'cap_net_bind_service=ep' in result.stdout:
|
|
print("✓ Port binding capabilities already set")
|
|
return True
|
|
|
|
# Try to set capabilities
|
|
print("Setting up port 80 binding capabilities...")
|
|
setup_script = './setup_port_capability.sh'
|
|
|
|
if os.path.exists(setup_script):
|
|
result = subprocess.run(['sudo', 'bash', setup_script], capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print("✓ Port capabilities set successfully")
|
|
return True
|
|
else:
|
|
print(f"✗ Failed to set capabilities: {result.stderr}")
|
|
|
|
except Exception as e:
|
|
print(f"Warning: Could not check port capabilities: {e}")
|
|
|
|
print("Warning: Port 80 may not be accessible. App will try to run on default port.")
|
|
return False
|
|
|
|
|
|
def check_hardware_interfaces():
|
|
"""Check hardware interfaces (UART/Serial) for RFID reader"""
|
|
print("Checking hardware interfaces...")
|
|
|
|
available_devices = []
|
|
|
|
for device in SERIAL_DEVICES:
|
|
if os.path.exists(device):
|
|
try:
|
|
with open(device, 'r'):
|
|
pass
|
|
available_devices.append(device)
|
|
print(f"✓ Serial device available: {device}")
|
|
except PermissionError:
|
|
print(f"✗ Permission denied for {device}. Adding user to dialout group...")
|
|
try:
|
|
username = pwd.getpwuid(os.getuid()).pw_name
|
|
subprocess.run(['sudo', 'usermod', '-a', '-G', 'dialout', username],
|
|
capture_output=True, text=True)
|
|
print(f"✓ User {username} added to dialout group (reboot may be required)")
|
|
available_devices.append(device)
|
|
except Exception as e:
|
|
print(f"✗ Failed to add user to dialout group: {e}")
|
|
except Exception as e:
|
|
print(f"Warning: Could not test {device}: {e}")
|
|
|
|
if not available_devices:
|
|
print("✗ No serial devices found. RFID reader may not work.")
|
|
try:
|
|
config_file = '/boot/config.txt'
|
|
if os.path.exists(config_file):
|
|
print("Attempting to enable UART in Raspberry Pi config...")
|
|
result = subprocess.run(['sudo', 'raspi-config', 'nonint', 'do_serial', '0'],
|
|
capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print("✓ UART enabled in config (reboot required)")
|
|
else:
|
|
print("Warning: Could not enable UART automatically")
|
|
except Exception as e:
|
|
print(f"Warning: Could not configure UART: {e}")
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
def initialize_gpio_permissions():
|
|
"""Set up GPIO permissions for LED control"""
|
|
print("Setting up GPIO permissions...")
|
|
|
|
try:
|
|
username = pwd.getpwuid(os.getuid()).pw_name
|
|
|
|
# Check if gpio group exists
|
|
try:
|
|
grp.getgrnam('gpio')
|
|
subprocess.run(['sudo', 'usermod', '-a', '-G', 'gpio', username],
|
|
capture_output=True, text=True)
|
|
print(f"✓ User {username} added to gpio group")
|
|
except KeyError:
|
|
print("Warning: gpio group not found - GPIO access may be limited")
|
|
|
|
# Set up GPIO access via /dev/gpiomem if available
|
|
for device in GPIO_DEVICES:
|
|
if os.path.exists(device):
|
|
print(f"✓ GPIO device available: {device}")
|
|
return True
|
|
|
|
print("Warning: No GPIO devices found")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"Warning: Could not set up GPIO permissions: {e}")
|
|
return False
|
|
|
|
|
|
def check_network_connectivity():
|
|
"""Check network connectivity and DNS resolution"""
|
|
print("Checking network connectivity...")
|
|
|
|
try:
|
|
# Test basic connectivity
|
|
result = subprocess.run(['ping', '-c', '1', '8.8.8.8'],
|
|
capture_output=True, text=True, timeout=5)
|
|
if result.returncode == 0:
|
|
print("✓ Internet connectivity available")
|
|
|
|
# Test DNS resolution
|
|
try:
|
|
import socket
|
|
socket.gethostbyname('google.com')
|
|
print("✓ DNS resolution working")
|
|
return True
|
|
except socket.gaierror:
|
|
print("✗ DNS resolution failed")
|
|
return False
|
|
else:
|
|
print("✗ No internet connectivity")
|
|
return False
|
|
|
|
except subprocess.TimeoutExpired:
|
|
print("✗ Network timeout")
|
|
return False
|
|
except Exception as e:
|
|
print(f"Warning: Could not test network: {e}")
|
|
return False
|
|
|
|
|
|
def create_required_files():
|
|
"""Create required data files with defaults if they don't exist"""
|
|
print("Checking required files...")
|
|
|
|
from config_settings import ID_MASA_FILE, TAG_FILE, DATA_DIR
|
|
|
|
required_files = {
|
|
str(ID_MASA_FILE): "unknown",
|
|
str(TAG_FILE): ""
|
|
}
|
|
|
|
for file_path, default_content in required_files.items():
|
|
try:
|
|
if not os.path.exists(file_path):
|
|
os.makedirs(os.path.dirname(file_path), exist_ok=True)
|
|
with open(file_path, 'w') as f:
|
|
f.write(default_content)
|
|
print(f"✓ Created default file: {file_path}")
|
|
else:
|
|
print(f"✓ File exists: {file_path}")
|
|
except Exception as e:
|
|
print(f"✗ Failed to create file {file_path}: {e}")
|
|
|
|
# Set file permissions
|
|
try:
|
|
for file_path in required_files.keys():
|
|
if os.path.exists(file_path):
|
|
os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
|
|
print("✓ File permissions set correctly")
|
|
except Exception as e:
|
|
print(f"Warning: Could not set file permissions: {e}")
|
|
|
|
return True
|
|
|
|
|
|
def perform_system_initialization():
|
|
"""Perform complete system initialization for first run"""
|
|
print("=" * 60)
|
|
print("SYSTEM INITIALIZATION - Preparing for first run")
|
|
print("=" * 60)
|
|
|
|
initialization_steps = [
|
|
("System Requirements", check_system_requirements),
|
|
("File Creation", create_required_files),
|
|
("Port Capabilities", check_port_capabilities),
|
|
("Hardware Interfaces", check_hardware_interfaces),
|
|
("GPIO Permissions", initialize_gpio_permissions),
|
|
("Network Connectivity", check_network_connectivity)
|
|
]
|
|
|
|
success_count = 0
|
|
total_steps = len(initialization_steps)
|
|
|
|
for step_name, step_function in initialization_steps:
|
|
print(f"\n--- {step_name} ---")
|
|
try:
|
|
if step_function():
|
|
success_count += 1
|
|
print(f"✓ {step_name} completed successfully")
|
|
else:
|
|
print(f"⚠ {step_name} completed with warnings")
|
|
except Exception as e:
|
|
print(f"✗ {step_name} failed: {e}")
|
|
|
|
print("\n" + "=" * 60)
|
|
print(f"INITIALIZATION COMPLETE: {success_count}/{total_steps} steps successful")
|
|
print("=" * 60)
|
|
|
|
if success_count < total_steps:
|
|
print("Warning: Some initialization steps failed. Application may have limited functionality.")
|
|
|
|
return success_count >= (total_steps - 1) # Allow one failure
|