Struct DataLogger

Source
pub struct DataLogger {
Show 22 fields config: DataLoggerConfig, lock_error_get_timestamp: bool, lock_error_output_state_refill_in_progress: bool, lock_error_output_state_heating_is_on: bool, lock_error_output_state_ventilation_is_on: bool, lock_error_output_signal_water_temperature: bool, lock_error_output_signal_pH: bool, lock_error_output_signal_conductivity: bool, lock_error_output_signal_ambient_temperature: bool, lock_error_output_signal_humidity: bool, lock_error_output_state_tank_level_switch_position: bool, lock_error_output_state_tank_level_switch_invalid: bool, lock_error_output_state_tank_level_switch_position_stabilized: bool, lock_error_output_signal_water_temperature_filtered: bool, lock_error_output_signal_pH_filtered: bool, lock_error_output_signal_conductivity_filtered: bool, lock_error_output_timestamp: bool, pub lock_warn_inapplicable_command_signal_handler: bool, pub lock_error_channel_receive_termination: bool, pub last_ping_instant: Instant, pub database_ping_interval: Duration, lock_error_mutex_signal_manager: bool,
}
Expand description

Contains the configuration and the implementation for regular data logging to SQL database and writing to the file (in RAM disk). Thread communication is as follows:

graph LR atlas_scientific[AtlasScientific] -.-> data_logger ambient[Ambient] -.-> data_logger tank_level_switch[TankLevelSwitch] --> data_logger refill[Refill control] -.-> data_logger ventilation[Ventilation control] --> data_logger data_logger --> signal_handler[Signal handler] signal_handler[Signal handler] --> data_logger

Fields§

§config: DataLoggerConfig

configuration data for the data logger

§lock_error_get_timestamp: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to create the timestamp

§lock_error_output_state_refill_in_progress: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write refill in progress to disk

§lock_error_output_state_heating_is_on: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write heating is on to disk

§lock_error_output_state_ventilation_is_on: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write ventilation is on to disk

§lock_error_output_signal_water_temperature: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write water temperature to disk

§lock_error_output_signal_pH: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write pH to disk

§lock_error_output_signal_conductivity: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write conductivity to disk

§lock_error_output_signal_ambient_temperature: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write ambient temperature to disk

§lock_error_output_signal_humidity: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write humidity to disk

§lock_error_output_state_tank_level_switch_position: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write tank level switch position to disk

§lock_error_output_state_tank_level_switch_invalid: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write tank level switch invalid to disk

§lock_error_output_state_tank_level_switch_position_stabilized: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write tank level switch position stabilized to disk

§lock_error_output_signal_water_temperature_filtered: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write temperature filtered to disk

§lock_error_output_signal_pH_filtered: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write pH filtered to disk

§lock_error_output_signal_conductivity_filtered: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write conductivity filtered to disk

§lock_error_output_timestamp: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to write timestamp to disk

§lock_warn_inapplicable_command_signal_handler: bool

an inhibition flag to avoid flooding the log file with repeated messages about having received an inapplicable command

§lock_error_channel_receive_termination: bool

an inhibition flag to avoid flooding the log file with repeated messages about failure to receive termination signal via the channel

§last_ping_instant: Instant

recording when the last database ping happened

§database_ping_interval: Duration

database ping interval

§lock_error_mutex_signal_manager: bool

Implementations§

Source§

impl DataLogger

Source

pub fn new( config: DataLoggerConfig, database_ping_interval: Duration, ) -> Result<DataLogger, DataLoggerError>

Creates a new DataLogger instance.

This constructor initializes the data logger module with its configuration. If output_to_disk is enabled, it validates that all required output file paths are non-empty and then resets each file by writing an empty string to it. It also initializes many internal “lock” flags designed to prevent log flooding.

§Arguments
  • config - Configuration data for the data logger, defining logging intervals, filter coefficients, output file paths, and other operational parameters.
  • database_ping_interval - A Duration instance, providing the interval to ping the database.
§Returns

A Result containing a new, initialized DataLogger instance on success.

§Errors

This function will return a DataLoggerError if output_to_disk is enabled and:

  • Any of the configured output filenames are empty (OutputFilenameEmpty).
  • It fails to write to (and thus reset) any of the configured output files, which could be due to permission issues or an invalid path (FileResetFailure).
Source

fn output_signal( &self, signal: f32, signal_type: AquariumSignal, output_file_name: &String, inhibit_error_log: bool, ) -> bool

Outputs a non-binary sensor signal to a specified file, typically located on a RAM disk.

This private helper function converts a floating-point signal into a human-readable string format (determined by signal_type) and attempts to write it to the given output_file_name. The operation only proceeds if output_to_disk is enabled in the data logger’s configuration.

Error logging for writing failures is managed by the inhibit_error_log flag, preventing a flood of repetitive error messages.

§Arguments
  • signal - The f32 sensor value to be written to the file.
  • signal_type - An AquariumSignal enum variant, used to determine the correct formatting for the signal value (e.g., number of decimal places).
  • output_file_name - A reference to the String containing the full path to the output file.
  • inhibit_error_log - A boolean flag that, if true, will prevent this specific error from being logged to the console/main log if a write operation fails.
§Returns

true if an error occurred during the file write operation; false otherwise (including when output_to_disk is false and no write is attempted).

Source

fn output_state( &self, state: bool, state_description_true: &str, state_description_false: &str, output_file_name: &String, inhibit_error_log: bool, ) -> bool

Outputs a boolean (binary) signal’s state to a specified file, typically located on a RAM disk.

This private helper function converts a boolean state into a descriptive string (e.g., “ON”/“OFF”, “HIGH”/“LOW”) using provided labels and attempts to write it to the given output_file_name. This operation only occurs if output_to_disk is enabled in the data logger’s configuration.

Error logging for writing failures is controlled by the inhibit_error_log flag, preventing a flood of repetitive error messages.

§Arguments
  • state - The bool value of the binary signal (e.g., true for ON, false for OFF).
  • state_description_true - The string label to write to the file when state is true.
  • state_description_false - The string label to write to the file when state is false.
  • output_file_name - A reference to the String containing the full path to the output file.
  • inhibit_error_log - A boolean flag that, if true, will prevent this specific error from being logged to the console/main log if a write operation fails.
§Returns
  • true: If an error occurred during the file write operation.
  • false: If the write-operation was successful or if output_to_disk is disabled.
Source

fn output_timestamp( &self, timestamp: NaiveDateTime, output_file_name: &String, inhibit_error_log: bool, ) -> bool

Outputs a NaiveDateTime timestamp to a specified file, typically located on a RAM disk.

This private helper function converts a NaiveDateTime into its string representation and attempts to write it to the given output_file_name. This operation only occurs if output_to_disk is enabled in the data logger’s configuration.

Error logging for writing failures is controlled by the inhibit_error_log flag, preventing a flood of repetitive error messages.

§Arguments
  • timestamp - The NaiveDateTime value to be written to the file.
  • output_file_name - A reference to the String containing the full path to the output file.
  • inhibit_error_log - A boolean flag that, if true, will prevent this specific error from being logged to the console/main log if a write operation fails.
§Returns
  • true: If an error occurred during the file write operation.
  • false: If the write-operation was successful or if output_to_disk is disabled.
Source

fn update_signals( &mut self, refill_status_live: &mut bool, refill_status_for_database: &mut bool, refill_reset_for_database: bool, heater_status: &mut bool, ventilation_status: &mut bool, data_logger_mutexes: &DataLoggerMutexes, )

Retrieves current ON/OFF status signals from Refill, Heating, and Ventilation control modules via channels.

This function sends a RequestSignal command to each of the specified control modules (Refill, Heating, Ventilation) and updates the provided status flags based on their responses. It also tracks channel disconnection status to prevent repeated errors.

§Arguments
  • refill_status - A mutable reference for indicating if the refill is in progress.
  • heater_status - A mutable reference for indicating the heater state.
  • ventilation_status - A mutable reference for indicating the ventilation state.
Source

fn update_sensor_manager_signals( &mut self, mutex_sensor_manager_signals: Arc<Mutex<SensorManagerSignals>>, water_temperature_opt: &mut Option<f32>, ph_opt: &mut Option<f32>, conductivity_opt: &mut Option<f32>, ambient_temperature_opt: &mut Option<f32>, humidity_opt: &mut Option<f32>, )

Retrieves current sensor readings from the SensorManager via a shared mutex and outputs them to files.

This private helper function locks the mutex_sensor_manager_signals to get the latest readings for water temperature, pH, conductivity, ambient temperature, and humidity. It updates the corresponding Option<f32> variables with the retrieved values and then calls output_signal to write these readings to their respective configured files on disk. If the mutex lock fails, an error is logged, and the function returns without updating the values.

§Arguments
  • mutex_sensor_manager_signals - An Arc<Mutex<SensorManagerSignals>> holding the latest sensor readings.
  • water_temperature_opt - A mutable reference to an Option<f32> where the retrieved water temperature will be stored.
  • ph_opt - A mutable reference to an Option<f32> where the retrieved pH value will be stored.
  • conductivity_opt - A mutable reference to an Option<f32> where the retrieved conductivity value will be stored.
  • ambient_temperature_opt - A mutable reference to an Option<f32> where the retrieved ambient temperature will be stored.
  • humidity_opt - A mutable reference to an Option<f32> where the retrieved humidity will be stored.
Source

fn update_tank_level_switch_signals( &mut self, mutex_tank_level_switch_signals: &Arc<Mutex<TankLevelSwitchSignals>>, tank_level_switch_position_opt: &mut Option<bool>, tank_level_switch_position_stabilized_opt: &mut Option<bool>, tank_level_switch_invalid_opt: &mut Option<bool>, )

Retrieves current signals from the TankLevelSwitch via a shared mutex and outputs them to files.

This private helper function locks the mutex_tank_level_switch_signals to get the latest state for the switch’s position, its stabilized position, and its invalid status. It updates the corresponding Option<bool> variables with the retrieved values and then calls output_state to write these states to their respective configured files on disk. If the mutex lock fails, the Option variables are set to None.

§Arguments
  • mutex_tank_level_switch_signals - An Arc<Mutex<TankLevelSwitchSignals>> holding the latest switch states.
  • tank_level_switch_position_opt - A mutable reference to an Option<bool> for the switch’s current position.
  • tank_level_switch_position_stabilized_opt - A mutable reference to an Option<bool> for the switch’s stabilized position.
  • tank_level_switch_invalid_opt - A mutable reference to an Option<bool> for the switch’s invalid status.
Source

fn calculate_filtered_signals( &mut self, water_temperature: Option<f32>, ph: Option<f32>, conductivity: Option<f32>, filter_water_temperature: &mut IIRFilter, filter_pH: &mut IIRFilter, filter_conductivity: &mut IIRFilter, ) -> (Option<f32>, Option<f32>, Option<f32>)

Calculates filtered values for water temperature, pH, and conductivity, then outputs them to files.

This private helper function takes raw (unfiltered) sensor readings. For each valid reading, it applies its corresponding IIRFilter to smooth the data. The resulting filtered values are then stored in new Option<f32> variables and written to their designated files on disk. If a raw reading is None, no filtering or output occurs for that signal.

§Arguments
  • water_temperature - The measured water temperature, wrapped in an Option.
  • ph - The measured pH value, wrapped in an Option.
  • conductivity - The measured conductivity value, wrapped in an Option.
§Returns

A tuple (Option<f32>, Option<f32>, Option<f32>) containing the filtered water temperature, pH, and conductivity values, respectively. Each value is Some if the corresponding input was valid and filtered, or None otherwise.

Source

fn update_timestamp(&mut self, conn: &mut PooledConn) -> NaiveDateTime

Retrieves the current timestamp, either from the SQL database or generated locally by the application.

This private helper function determines the timestamp source based on the use_sql_timestamp configuration setting. If use_sql_timestamp is true, it attempts to fetch the timestamp from the connected SQL database. If that fails, it falls back to using a locally generated timestamp and logs an error. If use_sql_timestamp is false, it always uses a local timestamp. The chosen timestamp is also written to a configured file on the disk.

§Arguments
  • conn - A mutable reference to an active SQL database connection, used if the SQL timestamp option is enabled.
§Returns

A NaiveDateTime representing the current timestamp, sourced either from the database or the local system.

Source

fn confirm_quit_and_wait_for_termination_command( &mut self, data_logger_channels: &mut DataLoggerChannels, )

Confirms the application’s readiness to quit and then waits for a specific termination command from the signal handler.

This function is called when the thread has received the Quit-command from the signal handler. It first sends a confirmation back to the signal handler, indicating that this component is ready to proceed with shutdown.

After confirming, it enters a loop, continuously listening for an InternalCommand::Terminate signal from the signal_handler. This ensures that the application’s internal threads, which might be listening to this component’s channels, stop receiving commands.

§Arguments
  • data_logger_channels - A mutable reference to the struct that contains the channels.
Source

pub fn execute( &mut self, data_injection: &mut impl DataInjectionTrait, sql_interface_data: SqlInterfaceData, data_logger_channels: &mut DataLoggerChannels, data_logger_mutexes: DataLoggerMutexes, )

Executes the main control loop for the data logger module.

This function runs continuously, acting as the central data collection and logging hub for the application. Before entering the loop, the function will set up Infinite Impulse Response (IIR) filters for various sensor signals.
The IIR filters for water temperature, pH, and conductivity are initialized with available data and a 1-second time step.

It performs the following key tasks in a recurring cycle:

  1. Signal Retrieval: Gathers current status (ON/OFF) from control modules (Refill, Heating, Ventilation) via channels.
  2. Sensor Data Acquisition: Reads raw sensor values (temperatures, pH, conductivity, ambient conditions, tank level switch states) from shared mutexes, which are updated by other sensor-reading threads.
  3. Signal Filtering: Applies IIR (Infinite Impulse Response) filters to sensor signals (e.g., water temperature, pH, conductivity) to produce smoothed values.
  4. Timestamping: Determines the current timestamp, either from the SQL database or generated locally, based on configuration.
  5. DataFrame Construction: Assembles all collected and processed data into a comprehensive RecorderDataFrame.
  6. Data Injection & Disk Output: Transfers the RecorderDataFrame to the SQL database (via the data_injection trait) and writes various individual signal/state values to designated files on a RAM disk (if configured).
  7. Cycle Management: Calculates the execution time of the current cycle and idles for the remaining duration to meet the configured logging_interval, ensuring precise data logging frequency. It warns if the cycle time is exceeded.
  8. Responsiveness: Remains responsive to Quit commands from the signal handler during idle periods to enable graceful shutdown.

The loop continues indefinitely until a Quit command is received from the signal handler. Upon receiving Quit, it performs a graceful exit sequence: sending confirmation back to the signal handler and then waiting for a Terminate command before finally exiting the thread.

§Arguments
  • data_injection - An object implementing the DataInjectionTrait, used for transferring the collected RecorderDataFrame to the SQL database or a mock data structure during testing.
  • sql_interface_data - A SqlInterfaceData instance, providing the direct interface for writing RecorderDataFrames to the SQL database.
  • data_logger_channels - A DataLoggerChannels struct, containing all the mpsc sender and receiver channels necessary for inter-thread communication with other modules and the signal handler.
  • data_logger_mutexes - A DataLoggerMutexes struct, providing access to shared Arc<Mutex> protected sensor data and device states.

Trait Implementations§

Source§

impl DatabasePingTrait for DataLogger

Source§

fn get_ping_interval(&self) -> Duration

Gets the interval at which the resource should be pinged.
Source§

fn get_last_ping_instant(&self) -> Instant

Gets the timestamp of the last successful ping.
Source§

fn update_last_ping_instant(&mut self)

Updates the timestamp of the last successful ping.
Source§

fn check_timing_and_ping_database( &mut self, database_interface: &mut (impl Pingable + ?Sized), )

Pings the database.
Source§

impl ProcessExternalRequestTrait for DataLogger

Source§

fn process_external_request( &mut self, rx_from_signal_handler: &mut AquaReceiver<InternalCommand>, _: Option<&mut AquaReceiver<InternalCommand>>, ) -> (bool, bool, bool)

Checks for and processes new commands relevant to the Data Logger module from external channels.

This is the specialized implementation of ProcessExternalRequestTrait for the DataLogger. It delegates directly to process_external_request_without_messaging, indicating that the DataLogger only processes commands from the signal handler and ignores any input from a messaging channel.

§Arguments
  • rx_from_signal_handler - A reference to the receiver end of the channel for commands originating from the signal handler.
  • _ - This parameter is ignored, as the DataLogger does not process messages from a messaging channel.
§Returns

A tuple (bool, bool, bool) indicating the status of commands received:

  • The first bool is true if a Quit command was received; otherwise false.
  • The second bool is always false (no “Start” commands processed).
  • The third bool is always false (no “Stop” commands processed).
Source§

impl WaitForTerminationTrait for DataLogger

Source§

fn get_warn_lock_mut(&mut self) -> &mut bool

Method connects the default trait implementation with the specific implementation accessing the warn-lock.

Source§

fn get_error_lock_mut(&mut self) -> &mut bool

Method connects the default trait implementation with the specific implementation for accessing the error-lock.

Source§

fn wait_for_termination( &mut self, rx_waiting_thread_from_signal_handler: &mut AquaReceiver<InternalCommand>, sleep_duration: Duration, origin: &str, )

Implements the graceful shutdown wait loop for several threads (default implementation). Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> MaybeSendSync for T