Skip to main content

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}