pub struct Controller { /* private fields */ }Expand description
The assembled, stateful decision logic of a profile’s built-in kind.
A controller is what a Profile turns its
ControlSpec into: the live loop that maps each reading to
a Reaction. It composes the pamoja-kit helpers - a
Thermostat for on/off control, a
Depletion predictor for level alerts, and a
Surge alarm for rapid change - so the same field-tested
math drives every profile. The logic is synchronous and
hardware-free, so a profile’s whole control policy is unit-testable with no
devices and no network. It implements Policy over an f32 reading and a
bool command, which is what lets a policy of your own stand in its place.
§Examples
use pamoja_profile::{Alert, Controller};
// Hold a fridge near 5 C, alerting if it strays more than 3 C from target.
let mut control = Controller::setpoint(5.0, 0.5, true, 3.0);
let reaction = control.evaluate(9.0); // warm and out of the safe band
assert_eq!(reaction.actuator, Some(true));
assert!(matches!(reaction.alert, Some(Alert::OutOfRange { .. })));Implementations§
Source§impl Controller
impl Controller
Sourcepub fn setpoint(
setpoint: f32,
hysteresis: f32,
cooling: bool,
safe_band: f32,
) -> Self
pub fn setpoint( setpoint: f32, hysteresis: f32, cooling: bool, safe_band: f32, ) -> Self
Builds a controller that holds a reading near a setpoint.
This is the policy behind “keep a temperature” and “keep the soil watered”:
it switches an output on and off around the setpoint and raises an
Alert::OutOfRange when the reading strays beyond safe_band.
§Arguments
setpoint- the target reading.hysteresis- half the deadband width around the setpoint, which stops the output chattering at the threshold.cooling-truefor an output that switches on above the band (a cooler),falsefor one that switches on below it (a heater or an irrigation valve).safe_band- how far the reading may stray from the setpoint before an alert fires.
§Returns
A controller whose output starts off.
Sourcepub fn level(empty: f32, warn_within: u32) -> Self
pub fn level(empty: f32, warn_within: u32) -> Self
Builds a controller that warns before a falling level runs out.
This is the policy behind “warn before a tank runs dry”: it watches a level
fall and raises an Alert::RunningOut once it is estimated to reach empty
within warn_within more samples.
§Arguments
empty- the level treated as empty, such as a dry tank.warn_within- warn once empty is this many samples away or nearer.
§Returns
A controller awaiting its first two readings.
Sourcepub fn surge(rising: bool, limit: f32) -> Self
pub fn surge(rising: bool, limit: f32) -> Self
Builds a controller that warns when a reading changes too fast.
This is the policy behind “warn me before it is too late”: it watches the
change between samples and raises an Alert::ChangingFast when a reading
moves more than limit per sample in the watched direction, such as a river
level rising into a flash flood.
§Arguments
rising- watch a rapid rise (true) or a rapid fall (false).limit- the largest safe change per sample.
§Returns
A controller awaiting its first reading.
Sourcepub fn monitor() -> Self
pub fn monitor() -> Self
Builds a controller that reports readings without driving an output.
§Returns
A controller that never commands an actuator and never alerts.
Sourcepub fn from_spec(spec: &ControlSpec) -> Result<Self>
pub fn from_spec(spec: &ControlSpec) -> Result<Self>
Assembles the controller a manifest’s control kind describes.
§Arguments
spec- the control policy a profile carries.
§Returns
A fresh controller with its control state reset.
§Errors
Returns [Error::Codec] for a custom kind, which has no built-in controller: its
policy is the code a PolicyRegistry resolves it to. Running one as a monitor
instead would leave a node that reports readings and never drives the output its
manifest promised.
Sourcepub fn evaluate(&mut self, reading: f32) -> Reaction
pub fn evaluate(&mut self, reading: f32) -> Reaction
Evaluates one reading and returns the action and any alert it calls for.
A controller remembers what it has seen: a setpoint whether its output is on, a level and a surge the previous reading. Keep one controller for the life of the node and hand it every reading in turn.
§Arguments
reading- the latest measured value, in real-world units. One that is not a finite number raisesAlert::InvalidReadingunder every kind but a monitor, and changes nothing.
§Returns
The Reaction for this reading: the actuator setting (if the profile drives
one) and any alert the reading raised.
Trait Implementations§
Source§impl Clone for Controller
impl Clone for Controller
Source§fn clone(&self) -> Controller
fn clone(&self) -> Controller
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more