pub struct Balling {
config: BallingConfig,
durations_until_next_dosing: [Duration; 4],
pump_is_active: [bool; 4],
dosing_intervals: [Duration; 4],
lock_error_channel_send_schedule_check: bool,
lock_error_channel_receive_schedule_check: bool,
pub execute_command_received: bool,
pub pump_id_requested: i32,
pub last_ping_instant: Instant,
pub database_ping_interval: Duration,
pub lock_warn_inapplicable_command_signal_handler: bool,
pub lock_error_channel_receive_termination: bool,
}Expand description
Contains the configuration and the implementation for the Balling dosing control. Thread communication of this component is as follows:
Fields§
§config: BallingConfigconfiguration data for Balling dosing control
durations_until_next_dosing: [Duration; 4]Durations until next dosing
pump_is_active: [bool; 4]Configuration data processed into an array: activation
dosing_intervals: [Duration; 4]Configuration data processed into an array: dosing intervals
lock_error_channel_send_schedule_check: boolinhibition flag to avoid flooding the log file with repeated messages to send request via the channel to schedule check
lock_error_channel_receive_schedule_check: boolinhibition flag to avoid flooding the log file with repeated messages to receive request via the channel from schedule check
execute_command_received: boolcommunication from trait implementation: request to execute a certain Balling mineral dosing has been received
pump_id_requested: i32communication from trait implementation: id of pump to be executed requested externally
last_ping_instant: Instantrecording when the last database ping happened
database_ping_interval: Durationdatabase ping interval
lock_warn_inapplicable_command_signal_handler: boolinhibition flag to avoid flooding the log file with repeated messages about having received inapplicable command via the channel
lock_error_channel_receive_termination: boolinhibition flag to avoid flooding the log file with repeated messages about failure to receive termination signal via the channel
Implementations§
Source§impl Balling
impl Balling
Sourcepub fn new(
config: BallingConfig,
database_ping_interval: Duration,
sql_interface_balling: &mut SqlInterfaceBalling,
) -> Result<Balling, BallingError>
pub fn new( config: BallingConfig, database_ping_interval: Duration, sql_interface_balling: &mut SqlInterfaceBalling, ) -> Result<Balling, BallingError>
Creates a new Balling control instance.
This constructor initializes the Balling dosing control module. It performs
several pre-flight checks, including validating the schedule_check_interval
and dosing intervals from the configuration, ensuring that a database entry
exists for every active pump, and calculating the initial countdowns for
each pump based on their last recorded dosing times.
§Arguments
config- Configuration data for the Balling dosing control, loaded from a TOML file.sql_interface_balling- A mutable reference to aSqlInterfaceBallinginstance, providing the specific SQL interface for Balling dosing operations.database_ping_interval- ADurationinstance, providing the interval to ping the database.
§Returns
A Result containing a new, initialized Balling instance on success.
§Errors
This function will return a BallingError if any of the initial setup steps fail:
- The
schedule_check_intervalin the configuration is zero (ScheduleCheckIntervalZero). - Any configured dosing interval is zero or shorter than the
schedule_check_interval(InvalidDosingInterval,DosingIntervalShorterThanCheckInterval). - A pump is marked as active in the config, but no corresponding set values are found
in the database (
SetValueRetrievalError). - It fails to calculate the initial countdown for any pump due to a database error or data conversion issue.
Sourcefn check_valid_dosing_intervals(
config: &BallingConfig,
) -> Result<(), BallingError>
fn check_valid_dosing_intervals( config: &BallingConfig, ) -> Result<(), BallingError>
Checks that configured dosing intervals are valid and logical.
This function validates two conditions for each active pump:
- The dosing interval must not be zero.
- The dosing interval must be greater than or equal to the
schedule_check_interval.
§Arguments
config- A reference to theBallingConfigcontaining the dosing intervals and the check interval.
§Returns
An empty Result (Ok(())) if all configured dosing intervals for active pumps are valid.
§Errors
This function will return a BallingError if an invalid configuration is detected:
InvalidDosingInterval: If an active pump’s dosing interval is set to0.DosingIntervalShorterThanCheckInterval: If an active pump’s dosing interval is shorter than the mainschedule_check_interval, which would lead to illogical scheduling.
Sourcefn check_database_vs_config(
sql_interface_balling: &mut SqlInterfaceBalling,
config: &BallingConfig,
) -> Result<(), BallingError>
fn check_database_vs_config( sql_interface_balling: &mut SqlInterfaceBalling, config: &BallingConfig, ) -> Result<(), BallingError>
Verifies that a database entry exists for every pump marked as active in the configuration.
This function ensures that the application doesn’t try to operate a pump that lacks the necessary set values (e.g., flow rate, volume) in the database.
§Arguments
sql_interface_balling- A mutable reference to theSqlInterfaceBallinginstance.config- A reference to theBallingConfigto check which pumps are active.
§Returns
An empty Result (Ok(())) if a database entry is found for every active pump.
§Errors
Returns BallingError::SetValueRetrievalError if an active pump is missing its
corresponding configuration entry in the ballingsetvals table. The error will
wrap the underlying SqlInterfaceError.
Sourcefn get_target_dosing_interval(
config: &BallingConfig,
pump_id: i64,
) -> Result<u32, BallingError>
fn get_target_dosing_interval( config: &BallingConfig, pump_id: i64, ) -> Result<u32, BallingError>
Retrieves the configured dosing interval for a specific pump.
§Arguments
config- A reference to theBallingConfigcontaining the dosing intervals.pump_id- The ID of the pump (1, 2, 3, or 4) for which to get the interval.
§Returns
A Result containing the configured dosing interval (u32) in seconds for the specified pump.
§Errors
Returns BallingError::CountdownCalculationInvalidPumpId if the provided pump_id
is not one of the recognized values (1, 2, 3, or 4).
Sourcefn calc_duration_until_next_dosing(
config: &BallingConfig,
sql_interface_balling: &mut SqlInterfaceBalling,
pump_id: i64,
) -> Result<Duration, BallingError>
fn calc_duration_until_next_dosing( config: &BallingConfig, sql_interface_balling: &mut SqlInterfaceBalling, pump_id: i64, ) -> Result<Duration, BallingError>
Calculates the remaining time (countdown) until the next scheduled dosing for a specific pump.
This function determines how much time is left until a pump’s next dosing event. It retrieves the target interval from the configuration and the elapsed time since the last dosing from the database. The duration is the interval minus the elapsed time. If no previous dosing event exists, the duration is set to the target interval applying a cautious strategy.
§Arguments
config- A reference to theBallingConfigcontaining the dosing intervals.sql_interface_balling- A mutable reference to theSqlInterfaceBallinginstance.pump_id- The unique identifier of the pump (1-4) for which to calculate the countdown.
§Returns
A Result containing the calculated duration until the next dosing. This value is 0 if the dosing is overdue.
§Errors
This function will return a BallingError if:
- The
pump_idis invalid (CountdownCalculationInvalidPumpId). - The configured dosing interval for the pump is zero (
InvalidDosingInterval). - The database query to get the duration since the last dosing fails (
ReadDurationSinceLastDosingFailure). - The retrieved duration from the database is negative or cannot be converted to
u32(CalculateDurationSinceLastDosingFailure).
Sourcefn calc_target_dosing_duration_millis(balling_setval: &BallingSetVal) -> u32
fn calc_target_dosing_duration_millis(balling_setval: &BallingSetVal) -> u32
Calculates the target dosing duration in milliseconds based on the pump’s flow rate and desired volume.
This private helper function determines how long a dosing pump needs to run to dispense a specific volume of fluid, given its flow rate.
§Arguments
balling_setval- A reference to aBallingSetValstruct, which contains thedosing_speed(flow rate in ml/sec) anddosing_volume(target volume in ml).
§Returns
A u32 representing the calculated dosing duration in milliseconds.
Returns 0 if either dosing_speed or dosing_volume is zero or negative,
indicating that no dosing should occur due to invalid parameters.
Sourcefn calc_actual_dosing_volume(
balling_setval: &BallingSetVal,
actual_dosing_duration_millis: u32,
) -> f32
fn calc_actual_dosing_volume( balling_setval: &BallingSetVal, actual_dosing_duration_millis: u32, ) -> f32
Calculates the actual volume of fluid dosed based on the pump’s flow rate and the actual run duration.
This private helper function determines the precise volume dispensed, taking into account the pump’s calibrated flow rate and the actual time it was active.
§Arguments
balling_setval- A reference to aBallingSetValstruct, containing the pump’sdosing_speed(flow rate in ml/sec).actual_dosing_duration_millis- The actual duration (in milliseconds) that the pump was active.
§Returns
An f32 representing the actual volume of fluid dosed (in milliliters).
Returns 0.0 if dosing_speed is zero or negative, or if actual_dosing_duration_millis is zero,
indicating that no fluid was dispensed.
Sourcefn execute_dosing(
&mut self,
pump_id: u32,
pump_device: AquariumDevice,
mineral_injection: &mut impl MineralInjectionTrait,
balling_channels: &mut BallingChannels,
sql_interface_balling: &mut SqlInterfaceBalling,
) -> bool
fn execute_dosing( &mut self, pump_id: u32, pump_device: AquariumDevice, mineral_injection: &mut impl MineralInjectionTrait, balling_channels: &mut BallingChannels, sql_interface_balling: &mut SqlInterfaceBalling, ) -> bool
Orchestrates the dosing process for a specific peristaltic pump.
This function performs the complete cycle of a dosing event:
- Retrieve the pump’s set values (e.g., flow rate, target volume) from the database.
- Calculates the required dosing duration.
- Invokes the
mineral_injectiontrait method to physically actuate the pump for the calculated duration. - Calculate the actual volume dosed based on the actual run time.
- Log the completed Balling dosing event, including the actual volume, back to the database.
The function also monitors for a Quit command from the signal handler during the injection process.
§Arguments
pump_id- The unique numerical ID of the peristaltic pump to be actuated (e.g., 1, 2, 3, 4).pump_device- TheAquariumDeviceenum variant corresponding to thepump_id, representing the physical device.mineral_injection- A mutable reference to an object implementingMineralInjectionTrait, responsible for the physical control of the pump.balling_channels- A mutable reference toBallingChannelsstruct containing all necessarympscsql_interface_balling- A mutable reference to aSqlInterfaceBallinginstance, providing the specific SQL interface for Balling dosing operations. This is moved into the struct.
§Returns
A bool which is true if a Quit command was received from the signal handler
during the dosing process, indicating that the application should shut down; otherwise false.
Sourcepub fn get_pump_from_id(pump_id: i32) -> Option<(u32, AquariumDevice)>
pub fn get_pump_from_id(pump_id: i32) -> Option<(u32, AquariumDevice)>
Selects the appropriate peristaltic pump and its corresponding device representation based on a given ID.
This function acts as a mapping from a numerical pump ID
to a tuple containing the pump’s u32 ID and its AquariumDevice enum variant.
Numerical pump IDs are used in external commands and in the database.
§Arguments
pump_id- The numerical ID of the pump (e.g., 1, 2, 3, 4) to be selected.
§Returns
An Option<(u32, AquariumDevice)>:
Some((u32, AquariumDevice)): If thepump_idmatches one of the known peristaltic pumps, it will return itsu32ID and the correspondingAquariumDevicevariant.None: If the providedpump_iddoes not correspond to a known peristaltic pump.
Sourcepub fn execute(
&mut self,
mutex_device_scheduler_balling: Arc<Mutex<i32>>,
balling_channels: &mut BallingChannels,
mineral_injection: &mut impl MineralInjectionTrait,
sql_interface_balling: SqlInterfaceBalling,
)
pub fn execute( &mut self, mutex_device_scheduler_balling: Arc<Mutex<i32>>, balling_channels: &mut BallingChannels, mineral_injection: &mut impl MineralInjectionTrait, sql_interface_balling: SqlInterfaceBalling, )
Executes the main control loop for the Balling dosing module.
This function runs continuously, managing the automatic dosing schedule for multiple peristaltic pumps, processing external commands, and ensuring a graceful shutdown. It periodically checks the dosing countdowns for each pump and, if due, initiates the dosing process, respecting schedule limitations.
The loop continues until a Quit command is received from the signal handler.
After exiting the main loop, it sends a confirmation back to the signal handler
and then waits for a Terminate command to complete its shutdown sequence.
§Arguments
mutex_device_scheduler_balling- AnArc<Mutex<i32>>used for coordinating access to device scheduling, preventing parallel actuation across different control modules. It holds a counter of the completed actuation.balling_channels- A mutable reference toBallingChannelsstruct containing all necessarympscsender and receiver channels for inter-thread communication (e.g., with the signal handler, relay manager, and schedule checker).mineral_injection- A mutable reference to an object implementing theMineralInjectionTrait, responsible for the physical control of the dosing pumps.sql_interface_balling- ASqlInterfaceBallinginstance, providing the specific SQL interface for Balling dosing operations.
Trait Implementations§
Source§impl DatabasePingTrait for Balling
impl DatabasePingTrait for Balling
Source§fn get_ping_interval(&self) -> Duration
fn get_ping_interval(&self) -> Duration
Source§fn get_last_ping_instant(&self) -> Instant
fn get_last_ping_instant(&self) -> Instant
Source§fn update_last_ping_instant(&mut self)
fn update_last_ping_instant(&mut self)
Source§fn check_timing_and_ping_database(
&mut self,
database_interface: &mut (impl Pingable + ?Sized),
)
fn check_timing_and_ping_database( &mut self, database_interface: &mut (impl Pingable + ?Sized), )
Source§impl ProcessExternalRequestTrait for Balling
impl ProcessExternalRequestTrait for Balling
Source§fn process_external_request(
&mut self,
rx_from_signal_handler: &mut AquaReceiver<InternalCommand>,
rx_from_messaging_opt: Option<&mut AquaReceiver<InternalCommand>>,
) -> (bool, bool, bool)
fn process_external_request( &mut self, rx_from_signal_handler: &mut AquaReceiver<InternalCommand>, rx_from_messaging_opt: Option<&mut AquaReceiver<InternalCommand>>, ) -> (bool, bool, bool)
Checks for and processes new commands relevant to the Balling control module from external channels.
This is the specialized implementation of ProcessExternalRequestTrait for the Balling module.
It handles standard “Terminate” or “Quit” commands from the signal handler.
From the messaging channel, it specifically processes “Start,” “Stop,” and “Execute” commands,
updating internal state variables (execute_command_received, pump_id_requested) based on these commands.
Inapplicable commands are ignored with warnings.
§Arguments
rx_from_signal_handler- A reference to the receiver end of the channel for commands originating from the signal handler.rx_from_messaging_opt- AnOptioncontaining a reference to the receiver end of the channel for commands from the messaging system. This channel is optional.
§Returns
A tuple (bool, bool, bool) indicating the status of specific commands received:
- The first
boolistrueif aQuitorTerminatecommand was received from the signal handler; otherwisefalse. - The second
boolistrueif aStartcommand was received from messaging; otherwisefalse. - The third
boolistrueif aStopcommand was received from messaging; otherwisefalse.
Source§impl WaitForTerminationTrait for Balling
impl WaitForTerminationTrait for Balling
Source§fn get_warn_lock_mut(&mut self) -> &mut bool
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
fn get_error_lock_mut(&mut self) -> &mut bool
Method connects the default trait implementation with the specific implementation for accessing the error-lock.