frequenz_microgrid_component_graph/operational_mode.rs
1// License: MIT
2// Copyright © 2026 Frequenz Energy-as-a-Service GmbH
3
4//! This module defines the [`OperationalMode`] enum, which describes whether a
5//! component is active and whether it provides telemetry, accepts control
6//! commands, or both.
7
8use std::fmt::Display;
9
10/// The operational mode of a component.
11///
12/// Mirrors the `ElectricalComponentOperationalMode` enum in the microgrid API.
13/// It indicates whether a component is active and operational, and whether it
14/// provides telemetry data, accepts control commands, or both.
15///
16/// A component that does not provide telemetry (see [`Self::provides_telemetry`])
17/// cannot be a measurement source in a formula, but it can still be used to
18/// classify the meter that measures it (e.g. as a PV meter or a CHP meter).
19#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
20pub enum OperationalMode {
21 /// The operational mode is not explicitly set.
22 ///
23 /// Treated as if the component provides telemetry. A component with an
24 /// unknown mode stays usable as a measurement source in formulas.
25 #[default]
26 Unspecified,
27 /// The component is inactive and not operational. It does not provide
28 /// telemetry data, and it does not accept control commands.
29 Inactive,
30 /// The component is active and operational. It only provides telemetry data,
31 /// and it does not accept control commands.
32 TelemetryOnly,
33 /// The component is active and operational. It only accepts control commands,
34 /// and it does not provide telemetry data.
35 ControlOnly,
36 /// The component is active and operational. It provides telemetry data and
37 /// accepts control commands.
38 ControlAndTelemetry,
39}
40
41impl OperationalMode {
42 /// Returns `true` if a component in this mode provides telemetry data.
43 ///
44 /// [`Self::Unspecified`] is treated as providing telemetry: when the mode is
45 /// unknown the component keeps the default behavior of being usable as a
46 /// measurement source.
47 pub fn provides_telemetry(self) -> bool {
48 match self {
49 OperationalMode::Unspecified
50 | OperationalMode::TelemetryOnly
51 | OperationalMode::ControlAndTelemetry => true,
52 OperationalMode::Inactive | OperationalMode::ControlOnly => false,
53 }
54 }
55}
56
57impl Display for OperationalMode {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 match self {
60 OperationalMode::Unspecified => write!(f, "Unspecified"),
61 OperationalMode::Inactive => write!(f, "Inactive"),
62 OperationalMode::TelemetryOnly => write!(f, "TelemetryOnly"),
63 OperationalMode::ControlOnly => write!(f, "ControlOnly"),
64 OperationalMode::ControlAndTelemetry => write!(f, "ControlAndTelemetry"),
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_provides_telemetry() {
75 // Modes that provide telemetry (Unspecified assumed to, for backward
76 // compatibility).
77 for mode in [
78 OperationalMode::Unspecified,
79 OperationalMode::TelemetryOnly,
80 OperationalMode::ControlAndTelemetry,
81 ] {
82 assert!(mode.provides_telemetry(), "{mode} should provide telemetry");
83 }
84
85 // Modes that do not provide telemetry.
86 for mode in [OperationalMode::Inactive, OperationalMode::ControlOnly] {
87 assert!(
88 !mode.provides_telemetry(),
89 "{mode} should not provide telemetry"
90 );
91 }
92 }
93
94 #[test]
95 fn test_default_is_unspecified() {
96 assert_eq!(OperationalMode::default(), OperationalMode::Unspecified);
97 }
98}