Skip to main content

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}