bhtune_cli/commands/tune/
mod.rs1mod 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}