Function run

Source
pub(crate) fn run() -> Result<(), StartupError>
Expand description

The main entry point of the Aquarium Control application.

This function initializes and orchestrates all modules of the control system. It performs the following high-level steps:

  1. Sets up global logging and handles command-line arguments for configuration file selection.
  2. Checks if the user has provided specific command line parameters and acts accordingly.
  3. Checks if the user has root privileges.
  4. Loads the application configuration from the specified .toml file.
  5. Publishes the application’s Process ID (PID) to a file and sets up a custom panic hook for cleanup.
  6. Performs version checks against the database to ensure compatibility.
  7. Initializes all SQL database interfaces and validates database readiness.
  8. Sets up all inter-thread communication channels (mpsc).
  9. Initializes all application modules (sensors, controls, managers) with their respective configurations and channels/mutexes.
  10. Spawns each module in its own dedicated thread within a std::thread::scope for structured concurrency.
  11. Manages the initial data acquisition phase, waiting for sensors to provide first readings before control loops become fully active.

This function is responsible for the overall lifecycle of the application, including graceful startup and panic handling.

§Returns

An empty Result (Ok(())) on a graceful shutdown. This occurs if the user provides a command-line flag like -h or if the application is terminated normally by the signal handler.

§Errors

Returns a StartupError if any part of the initialization or setup fails. This error enum covers a wide range of potential issues, including:

  • StartupError::Config: If the configuration file is invalid or cannot be parsed.
  • StartupError::LoggingSetupFailure: If the logger cannot be initialized (e.g., due to file permissions).
  • StartupError::NotRoot: If the application is run without the necessary root privileges.
  • StartupError::PidCheckError: If another instance is already running or the PID file cannot be written.
  • StartupError::Database: If any database connection, query, or setup fails.
  • StartupError::GpioHandlerSetupFailure: If the GPIO interface cannot be initialized on the target hardware.
  • And various other setup failures for specific modules.

Global thread communication is as follows:

graph LR tank_level_switch -.-> refill[Refill] refill --> relay_manager[Controllino] relay_manager --> refill sensor_manager[SensorManager] -.-> data_logger[DataLogger] refill -.-> data_logger signal_handler[SignalHandler] --> refill refill --> signal_handler signal_handler --> tank_level_switch tank_level_switch --> signal_handler signal_handler --> tcp_communication[TcpCommunication] tcp_communication --> signal_handler signal_handler --> relay_manager relay_manager --> signal_handler balling[Balling] --> signal_handler signal_handler --> balling feed[Feed] --> signal_handler signal_handler --> feed heating[Heating] --> signal_handler signal_handler --> heating ventilation[Ventilation] --> signal_handler signal_handler --> ventilation relay_manager --> tcp_communication sensor_manager --> tcp_communication tcp_communication --> sensor_manager atlas_scientific --> tcp_communication tcp_communication --> atlas_scientific tank_level_switch --> tcp_communication tcp_communication --> tank_level_switch balling --> relay_manager relay_manager --> balling feed --> relay_manager relay_manager --> feed atlas_scientific -.-> data_logger heating -.-> data_logger atlas_scientific -.-> heating heating --> relay_manager relay_manager --> heating tank_level_switch -.-> heating sensor_manager -.-> heating tank_level_switch -.-> data_logger ventilation -.-> data_logger signal_handler --> data_logger data_logger --> signal_handler ventilation --> relay_manager atlas_scientific -.-> ventilation relay_manager --> ventilation monitors[Monitors] --> relay_manager relay_manager --> monitors monitors --> refill refill --> monitors monitors --> signal_handler signal_handler --> monitors ventilation --> schedule_check[ScheduleCheck] schedule_check --> ventilation heating --> schedule_check schedule_check --> heating refill --> schedule_check schedule_check --> refill balling --> schedule_check schedule_check --> balling signal_handler --> schedule_check schedule_check --> signal_handler signal_handler --> messaging[Messaging] signal_handler --> sensor_manager signal_handler --> watchdog sensor_manager --> signal_handler signal_handler --> atlas_scientific atlas_scientific --> signal_handler atlas_scientific --> i2c_interface[I2C interface] i2c_interface --> atlas_scientific dht -.-> sensor_manager messaging --> refill messaging --> ventilation messaging --> heating messaging --> balling messaging --> feed messaging --> monitors messaging --> watchdog