Skip to main content

bhtune_cli/commands/tune/
mod.rs

1//! CLI adapter for the shared tune runtime.
2
3mod output;
4
5pub use output::TuneOutcome;
6
7use bhtune_db::SqlitePool;
8use bhtune_runtime::cancel::CtrlC;
9use bhtune_runtime::config::BhtuneConfig;
10use bhtune_runtime::tune::{ValidatedTuneRequest, drive_report, prepare};
11
12use crate::args::TuneArgs;
13
14pub use bhtune_runtime::tune::{PidWriteOutcome, write_pid_values};
15
16pub(crate) async fn run_with_ctrl_c(
17    pool: &SqlitePool,
18    args: TuneArgs,
19    config: &BhtuneConfig,
20    ctrl_c: &mut CtrlC,
21) -> anyhow::Result<TuneOutcome> {
22    let output_format = args.output;
23    let requested_write_pid = args.write_pid.map(Into::into);
24
25    #[cfg(test)]
26    let config = {
27        let mut config = config.clone();
28        config.tuning.mrft_delay_secs = Some(args.mrft_delay);
29        config.tuning.poll_interval_ms = Some(args.poll_interval_ms);
30        config.tuning.timeout_secs = Some(args.timeout_secs);
31        config.tuning.op_timeout_secs = Some(args.op_timeout_secs);
32        config.tuning.restore_timeout_secs = Some(args.restore_timeout_secs);
33        config
34    };
35
36    #[cfg(not(test))]
37    let config = config.clone();
38
39    let request = ValidatedTuneRequest::try_from(args)?;
40    let prepared = prepare(pool, request, &config).await?;
41    let mut handler = output::CliWriteBackHandler::new(output_format, requested_write_pid);
42    let report = drive_report(pool, prepared, ctrl_c, Some(&mut handler)).await?;
43    Ok(output::print_summary(
44        report.run_id,
45        &report.outcome,
46        output_format,
47        &handler.previews,
48    ))
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use crate::args::{
55        ControllerTypeArg, DirectionArg, DriverKindArg, ProcessTypeArg, ResponseLevelArg,
56    };
57    use crate::output::OutputFormat;
58    use bhtune_core::{ControllerType, ProcessType, ResponseLevel};
59    use bhtune_runtime::tune::DriverKind;
60
61    #[test]
62    fn cli_tune_arguments_convert_to_validated_runtime_request() {
63        let request = ValidatedTuneRequest::try_from(TuneArgs {
64            tagname: "Unit1.LIC101.PV".to_string(),
65            template: "Honeywell".to_string(),
66            process_type: ProcessTypeArg::Flow,
67            controller_type: ControllerTypeArg::Pi,
68            relay_amp: 10.0,
69            cycles_skip: Some(1),
70            cycles_count: Some(2),
71            noise_protection_secs: Some(3),
72            mrft_delay: 0,
73            driver: DriverKindArg::Opcda,
74            bridge_host: Some("127.0.0.1:7600".to_string()),
75            server: Some("MockServer".to_string()),
76            sim_gain: 1.0,
77            sim_tau: 2.0,
78            sim_dead_time: 5.0,
79            sim_noise: 0.0,
80            sim_seed: 0,
81            sim_initial_pv: 50.0,
82            sim_initial_mv: 50.0,
83            pv_range_high: Some(100.0),
84            pv_range_low: Some(0.0),
85            mv_range_high: Some(100.0),
86            mv_range_low: Some(0.0),
87            direction: Some(DirectionArg::Reverse),
88            tag_overrides: None,
89            poll_interval_ms: 800,
90            timeout_secs: 3600,
91            op_timeout_secs: 30,
92            restore_timeout_secs: 30,
93            notes: Some("scheduled".to_string()),
94            yes: true,
95            write_pid: Some(ResponseLevelArg::Moderate),
96            output: OutputFormat::Json,
97        })
98        .unwrap();
99        let request = request.as_request();
100
101        assert_eq!(request.process_type, ProcessType::Flow);
102        assert_eq!(request.controller_type, ControllerType::Pi);
103        assert_eq!(
104            request.direction,
105            Some(bhtune_core::ControllerDirection::Reverse)
106        );
107        assert_eq!(request.driver, DriverKind::Opcda);
108        assert_eq!(request.write_pid, Some(ResponseLevel::Moderate));
109        assert_eq!(request.notes.as_deref(), Some("scheduled"));
110    }
111}