automation_hat/relay.rs
1//! Relay control for Automation HAT boards.
2//!
3//! This module provides control for the relay outputs on Automation HAT boards.
4//! Each relay has both normally open (NO) and normally closed (NC) terminals,
5//! and can be controlled with indicator LEDs showing the current state.
6
7use crate::lights::LED;
8
9use embedded_hal::digital::{OutputPin, PinState};
10use linux_embedded_hal::{
11 CdevPin,
12 gpio_cdev::{Line, LineRequestFlags},
13};
14
15/// Controls a relay output on the Automation HAT.
16///
17/// Each relay provides a high-power switch controlled by the Raspberry Pi.
18/// Relays have both normally open (NO) and normally closed (NC) terminals,
19/// which can be used to switch external circuits.
20pub struct Relay {
21 /// GPIO pin controlling the relay
22 pin: CdevPin,
23 /// LED indicating the normally open contact state
24 no_led: Option<LED>,
25 /// LED indicating the normally closed contact state
26 nc_led: Option<LED>,
27 /// Whether LEDs should automatically reflect the relay state
28 _auto_light: bool,
29 /// Current state of the relay (true = activated/on, false = deactivated/off)
30 pub value: bool,
31}
32
33impl Relay {
34 /// Creates a new relay instance with automatic LED indication enabled.
35 ///
36 /// # Arguments
37 ///
38 /// * `line` - GPIO line connected to the relay
39 /// * `no_led` - Optional LED for the normally open contact indicator
40 /// * `nc_led` - Optional LED for the normally closed contact indicator
41 ///
42 /// # Returns
43 ///
44 /// A new `Relay` instance configured with automatic LED indication
45 pub fn new(line: Line, no_led: Option<LED>, nc_led: Option<LED>) -> Self {
46 let line = line
47 .request(LineRequestFlags::OUTPUT, 0, "AutomationHAT Rust SDK")
48 .unwrap();
49 let pin = CdevPin::new(line).unwrap();
50 Relay {
51 pin,
52 no_led,
53 nc_led,
54 _auto_light: true,
55 value: false,
56 }
57 }
58
59 /// Creates a new relay instance with configurable LED indication.
60 ///
61 /// # Arguments
62 ///
63 /// * `line` - GPIO line connected to the relay
64 /// * `no_led` - Optional LED for the normally open contact indicator
65 /// * `nc_led` - Optional LED for the normally closed contact indicator
66 /// * `auto_light` - Whether LEDs should automatically reflect relay state
67 ///
68 /// # Returns
69 ///
70 /// A new `Relay` instance with the specified LED behavior
71 pub fn new_with_auto_light(
72 line: Line,
73 no_led: Option<LED>,
74 nc_led: Option<LED>,
75 auto_light: bool,
76 ) -> Self {
77 let line = line
78 .request(LineRequestFlags::OUTPUT, 0, "AutomationHAT Rust SDK")
79 .unwrap();
80 let pin = CdevPin::new(line).unwrap();
81 Relay {
82 pin,
83 no_led,
84 nc_led,
85 _auto_light: auto_light,
86 value: false,
87 }
88 }
89
90 /// Sets the state of the relay.
91 ///
92 /// When `open` is true, the relay is activated:
93 /// - The normally open (NO) contacts close
94 /// - The normally closed (NC) contacts open
95 /// - If auto_light is enabled, the NO LED lights up and NC LED turns off
96 ///
97 /// When `open` is false, the relay is deactivated:
98 /// - The normally open (NO) contacts open
99 /// - The normally closed (NC) contacts close
100 /// - If auto_light is enabled, the NO LED turns off and NC LED lights up
101 ///
102 /// # Arguments
103 ///
104 /// * `open` - The desired state of the relay (true = activated, false = deactivated)
105 ///
106 /// # Returns
107 ///
108 /// A `Result` indicating success or an error message if the operation failed
109 pub fn write(&mut self, open: bool) -> Result<(), &str> {
110 if self._auto_light {
111 let no_brightness = match open {
112 true => 1.0,
113 false => 0.0,
114 };
115 let nc_brightness = match open {
116 true => 0.0,
117 false => 1.0,
118 };
119 if self.no_led.is_some() {
120 let _ = self.no_led.as_mut().unwrap().set(no_brightness);
121 }
122 if self.nc_led.is_some() {
123 let _ = self.nc_led.as_mut().unwrap().set(nc_brightness);
124 }
125 }
126 match self.pin.set_state(match open {
127 true => PinState::High,
128 false => PinState::Low,
129 }) {
130 Ok(_) => {}
131 Err(_) => return Err("Unable to set value"),
132 };
133 self.value = open;
134 Ok(())
135 }
136}