From efac5ae09f2c4d6f8b513c23841f1e2b7171597c Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Fri, 13 Sep 2024 00:25:34 -0400 Subject: [PATCH 1/6] Added boilerplate for switch feature --- README.md | 10 ++++++++ src/http_server.rs | 16 +++++++++++- src/http_server/html_responses.rs | 38 ++++++++++++++++++++++++++-- src/http_server/wol_utils.rs | 42 +++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c3f817c..8942c20 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,10 @@ Set the following environment variables. These variables are used to configure t - `WOL_ENABLE`: A flag to enable or disable the WOL feature of the HTTP server. Set to "true" or "1" to enable. - `WOL_BROADCAST_ADDR`: The broadcast address to send Wake-on-LAN packets to. Typically set to "255.255.255.255" to broadcast to all devices on the local network. +**Switch Configuration** + +- `SWITCH_ENABLE`: A flag to enable or disable the Switch feature of the HTTP server. This uses the ESP32 as a computer power switch. Set to "true" or "1" to enable. + Here is an example of setting these variables: ```bash @@ -87,6 +91,9 @@ export HTTP_LISTEN_PORT="80" # For WOL export WOL_ENABLE="true" export WOL_BROADCAST_ADDR="255.255.255.255" + +# For Switch +export SWITCH_ENABLE="true" ``` Now, make sure that your current working directory (output of `pwd` command) is the root of the cloned repository. @@ -130,6 +137,9 @@ HTTP_LISTEN_PORT="80" WOL_ENABLE="true" WOL_BROADCAST_ADDR="255.255.255.255" +# For Switch +SWITCH_ENABLE="true" + # ... ``` diff --git a/src/http_server.rs b/src/http_server.rs index d6aeb93..9262c6a 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -9,7 +9,7 @@ use esp_backtrace as _; use esp_wifi::wifi::{WifiDevice, WifiStaDevice}; use heapless::FnvIndexMap; use html_responses::{HTML_HEADER, HTML_MENU, HTML_TAIL}; -use wol_utils::wol_command; +use wol_utils::{switch_command, wol_command}; /// The HTTP headers for the response. const HTTP_HEADERS: &[u8] = @@ -23,6 +23,8 @@ const HTTP_LISTEN_PORT_FALLBACK: u16 = 8080; const TCP_BUFFER_SIZE: usize = 4096; /// The enable flag for the WOL feature. const WOL_ENABLE: &str = env!("WOL_ENABLE"); +/// The enable flag for the Switch feature. +const SWITCH_ENABLE: &str = env!("SWITCH_ENABLE"); /// The embassy task that handles the HTTP server. #[embassy_executor::task] @@ -151,6 +153,18 @@ async fn handle_http_query( None => Ok(html_responses::WOL_INPUT), } } + "/switch" => { + if SWITCH_ENABLE != "true" && SWITCH_ENABLE != "1" { + return Ok(html_responses::NOT_ENABLED); + } + match args.get("gpio") { + Some(v) => { + switch_command(v).await?; + Ok(html_responses::SWITCH_SUCCESS) + } + None => Ok(html_responses::SWITCH_SELECT), + } + } _ => Ok(html_responses::HOME), } } diff --git a/src/http_server/html_responses.rs b/src/http_server/html_responses.rs index a5803af..3d7e870 100644 --- a/src/http_server/html_responses.rs +++ b/src/http_server/html_responses.rs @@ -1,5 +1,26 @@ pub const HOME: &[u8] = b""; +pub const SWITCH_SUCCESS: &[u8] = b"\ +

Switch

+

Switch activated!

"; + +pub const SWITCH_SELECT: &[u8] = b"\ +

Switch

+

Select the pin to use as a power switch

+
+
+ + +
+ + +
+ + +
+ +
"; + pub const WOL_INPUT: &[u8] = b"\

WOL

Insert the MAC address of the device to wake

@@ -32,6 +53,11 @@ pub const HTML_MENU: &[u8] = b"\ >WOL +
  • + Switch +
  • \r\n"; pub const HTML_HEADER: &[u8] = b"\ @@ -101,6 +127,11 @@ pub const HTML_HEADER: &[u8] = b"\ color: #fff090; } + input[type=\"radio\"] { + width: 1.5em; + height: 1.5em; + } + form { display: flex; flex-direction: column; @@ -125,7 +156,9 @@ pub const HTML_HEADER: &[u8] = b"\ } .arrow:hover, - input[type=\"submit\"]:hover { + label:hover, + input[type=\"submit\"]:hover, + input[type=\"radio\"]:hover { cursor: pointer; background-color: transparent; } @@ -137,6 +170,7 @@ pub const HTML_HEADER: &[u8] = b"\ left: -6em; } -\r\n"; + +\r\n"; pub const HTML_TAIL: &[u8] = b"\r\n\r\n\r\n"; diff --git a/src/http_server/wol_utils.rs b/src/http_server/wol_utils.rs index 7f26f6d..3cefd66 100644 --- a/src/http_server/wol_utils.rs +++ b/src/http_server/wol_utils.rs @@ -17,6 +17,48 @@ const WOL_BROADCAST_ADDR: &str = env!("WOL_BROADCAST_ADDR"); /// The fallback broadcast address to send the WOL packet to. const WOL_BROADCAST_ADDR_FALLBACK: IpAddress = IpAddress::v4(255, 255, 255, 255); +/// Triggers a GPIO pin set as an open drain +pub async fn switch_command(pin: &str) -> Result<(), ()> { + // Parse the pin number as a u8 + let pin = match pin.parse::() { + Ok(v) => v, + Err(_) => { + log::error!("Switch | Error parsing pin number"); + return Err(()); + } + }; + + // match pin { + // 2 => { + // let mut pin = OutputOpenDrain::new(io.pins.gpio2, Level::Low, Pull::None); + // + // pin.toggle(); + // Timer::after(Duration::from_millis(500)).await; + // pin.toggle(); + // } + // 3 => { + // let mut pin = Output::new(io.pins.gpio3, Level::Low); + // + // pin.toggle(); + // Timer::after(Duration::from_millis(500)).await; + // pin.toggle(); + // } + // 4 => { + // let mut pin = Output::new(io.pins.gpio4, Level::Low); + // + // pin.toggle(); + // Timer::after(Duration::from_millis(500)).await; + // pin.toggle(); + // } + // _ => { + // log::error!("Switch | Invalid pin number"); + // return Err(()); + // } + // } + + Ok(()) +} + /// Send a Wake-on-LAN command to the specified MAC address. pub async fn wol_command( stack: &'static Stack>, From 52449fc5b74b208912ff1c5a9393f08fa218dea4 Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Fri, 13 Sep 2024 00:51:42 -0400 Subject: [PATCH 2/6] Logging and formatting --- src/http_server/wol_utils.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/http_server/wol_utils.rs b/src/http_server/wol_utils.rs index 3cefd66..d888a2c 100644 --- a/src/http_server/wol_utils.rs +++ b/src/http_server/wol_utils.rs @@ -18,9 +18,9 @@ const WOL_BROADCAST_ADDR: &str = env!("WOL_BROADCAST_ADDR"); const WOL_BROADCAST_ADDR_FALLBACK: IpAddress = IpAddress::v4(255, 255, 255, 255); /// Triggers a GPIO pin set as an open drain -pub async fn switch_command(pin: &str) -> Result<(), ()> { +pub async fn switch_command(pin_str: &str) -> Result<(), ()> { // Parse the pin number as a u8 - let pin = match pin.parse::() { + let pin = match pin_str.parse::() { Ok(v) => v, Err(_) => { log::error!("Switch | Error parsing pin number"); @@ -56,6 +56,7 @@ pub async fn switch_command(pin: &str) -> Result<(), ()> { // } // } + log::info!("SWITCH | Triggered pin GPIO{}", pin_str); Ok(()) } From 4de13dfa4e114d1d96252506bcb658df894f9cf5 Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Fri, 13 Sep 2024 03:15:29 -0400 Subject: [PATCH 3/6] Added working GPIO pins --- Cargo.toml | 3 + README.md | 2 +- src/http_server/html_responses.rs | 17 ++- src/http_server/wol_utils.rs | 193 +++++++++++++++++++++++++----- src/main.rs | 22 ++++ src/pins.rs | 20 ++++ 6 files changed, 227 insertions(+), 30 deletions(-) create mode 100644 src/pins.rs diff --git a/Cargo.toml b/Cargo.toml index a3dcfa8..cda26c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ log = [ "dep:log", "embassy-executor/log", "embassy-futures/log", + "embassy-sync/log", "esp-backtrace/println", "esp-hal/log", "esp-println/log", @@ -28,6 +29,7 @@ defmt = [ "embassy-executor/defmt", "embassy-futures/defmt", "embassy-net/defmt", + "embassy-sync/defmt", "esp-backtrace/defmt", "esp-hal/defmt", "esp-println/defmt-espflash", @@ -41,6 +43,7 @@ defmt = { version = "0.3.8", optional = true } embassy-executor = { version = "0.6.0", features=["nightly"] } embassy-futures = "0.1.1" embassy-net = { version = "0.4.0", features = ["tcp", "udp", "dns", "dhcpv4", "dhcpv4-hostname", "medium-ethernet"] } +embassy-sync = "0.6.0" embassy-time = { version = "0.3.1", features=["generic-queue-8"] } esp-backtrace = { version = "0.14.1", features = ["panic-handler", "exception-handler"] } esp-hal = { version = "0.20.1" } diff --git a/README.md b/README.md index 8942c20..8b7f779 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Set the following environment variables. These variables are used to configure t **Switch Configuration** -- `SWITCH_ENABLE`: A flag to enable or disable the Switch feature of the HTTP server. This uses the ESP32 as a computer power switch. Set to "true" or "1" to enable. +- `SWITCH_ENABLE`: A flag to enable or disable the Switch feature of the HTTP server. This uses the ESP32 as a computer power switch. Set to "true" or "1" to enable. **If you use this as a power switch, make sure to properly configure the GPIO pins as Pull Up or Pull Down in the `./src/main.rs` file.** Here is an example of setting these variables: diff --git a/src/http_server/html_responses.rs b/src/http_server/html_responses.rs index 3d7e870..193518c 100644 --- a/src/http_server/html_responses.rs +++ b/src/http_server/html_responses.rs @@ -17,6 +17,21 @@ pub const SWITCH_SELECT: &[u8] = b"\
    +
    + + +
    + + +
    + + +
    + + +
    + + "; @@ -91,7 +106,7 @@ pub const HTML_HEADER: &[u8] = b"\ justify-content: center; align-items: center; text-align: center; - height: 100%; + height: 120%; background-color: #221; } diff --git a/src/http_server/wol_utils.rs b/src/http_server/wol_utils.rs index d888a2c..d459f59 100644 --- a/src/http_server/wol_utils.rs +++ b/src/http_server/wol_utils.rs @@ -1,5 +1,5 @@ +use crate::pins::*; use crate::utils::{convert_mac_address, parse_ip_address}; - use embassy_net::{ udp::{PacketMetadata, UdpSocket}, IpAddress, IpEndpoint, Stack, @@ -28,33 +28,170 @@ pub async fn switch_command(pin_str: &str) -> Result<(), ()> { } }; - // match pin { - // 2 => { - // let mut pin = OutputOpenDrain::new(io.pins.gpio2, Level::Low, Pull::None); - // - // pin.toggle(); - // Timer::after(Duration::from_millis(500)).await; - // pin.toggle(); - // } - // 3 => { - // let mut pin = Output::new(io.pins.gpio3, Level::Low); - // - // pin.toggle(); - // Timer::after(Duration::from_millis(500)).await; - // pin.toggle(); - // } - // 4 => { - // let mut pin = Output::new(io.pins.gpio4, Level::Low); - // - // pin.toggle(); - // Timer::after(Duration::from_millis(500)).await; - // pin.toggle(); - // } - // _ => { - // log::error!("Switch | Invalid pin number"); - // return Err(()); - // } - // } + let mut triggered = false; + match pin { + 2 => { + GPIO2.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO2.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 3 => { + GPIO3.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO3.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 4 => { + GPIO4.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO4.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 5 => { + GPIO5.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO5.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 6 => { + GPIO6.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO6.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 7 => { + GPIO7.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO7.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 8 => { + GPIO8.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO8.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + 9 => { + GPIO9.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + Timer::after(Duration::from_millis(500)).await; + GPIO9.lock(|x| { + if let Some(v) = x.borrow_mut().as_mut() { + v.toggle(); + triggered = true; + } else { + triggered = false; + } + }); + } + _ => { + log::error!("Switch | Invalid pin number"); + return Err(()); + } + } + + if !triggered { + log::error!("Switch | Error toggling pin GPIO{}", pin_str); + return Err(()); + } log::info!("SWITCH | Triggered pin GPIO{}", pin_str); Ok(()) diff --git a/src/main.rs b/src/main.rs index d3d54fd..1e2bd61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod dns; mod http_server; +mod pins; mod utils; use core::str::FromStr; @@ -14,6 +15,7 @@ use embassy_time::{Duration, Timer}; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + gpio::{Io, Level, OutputOpenDrain, Pull}, peripherals::Peripherals, prelude::*, riscv::singleton, @@ -34,6 +36,7 @@ use esp_wifi::{ EspWifiInitFor, }; use http_server::http_server_task; +use pins::*; /// The hostname of the device. const HOSTNAME: &str = env!("HOSTNAME"); @@ -58,10 +61,29 @@ async fn main(spawner: Spawner) { // Initialize the peripherals let peripherals = Peripherals::take(); + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); let mut rng = Rng::new(peripherals.RNG); + // Initialize GPIO pins + let gpio2 = OutputOpenDrain::new(io.pins.gpio2, Level::Low, Pull::Up); + let gpio3 = OutputOpenDrain::new(io.pins.gpio3, Level::Low, Pull::Up); + let gpio4 = OutputOpenDrain::new(io.pins.gpio4, Level::Low, Pull::Up); + let gpio5 = OutputOpenDrain::new(io.pins.gpio5, Level::Low, Pull::Up); + let gpio6 = OutputOpenDrain::new(io.pins.gpio6, Level::Low, Pull::Up); + let gpio7 = OutputOpenDrain::new(io.pins.gpio7, Level::Low, Pull::Up); + let gpio8 = OutputOpenDrain::new(io.pins.gpio8, Level::Low, Pull::Up); + let gpio9 = OutputOpenDrain::new(io.pins.gpio9, Level::Low, Pull::Up); + GPIO2.lock(|x| x.borrow_mut().replace(gpio2)); + GPIO3.lock(|x| x.borrow_mut().replace(gpio3)); + GPIO4.lock(|x| x.borrow_mut().replace(gpio4)); + GPIO5.lock(|x| x.borrow_mut().replace(gpio5)); + GPIO6.lock(|x| x.borrow_mut().replace(gpio6)); + GPIO7.lock(|x| x.borrow_mut().replace(gpio7)); + GPIO8.lock(|x| x.borrow_mut().replace(gpio8)); + GPIO9.lock(|x| x.borrow_mut().replace(gpio9)); + // Generate a seed for the wifi stack let mut seed_buf = [0u8; 8]; rng.read(&mut seed_buf); diff --git a/src/pins.rs b/src/pins.rs new file mode 100644 index 0000000..83a02ee --- /dev/null +++ b/src/pins.rs @@ -0,0 +1,20 @@ +use core::cell::RefCell; +use embassy_sync::blocking_mutex::{raw::CriticalSectionRawMutex, CriticalSectionMutex, Mutex}; +use esp_hal::gpio::{GpioPin, OutputOpenDrain}; + +pub static GPIO2: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO3: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO4: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO5: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO6: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO7: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO8: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); +pub static GPIO9: Mutex>>>> = + CriticalSectionMutex::new(RefCell::new(None)); From 051c5d23f63ba4038922d636c52c7e50782fbf2e Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Fri, 13 Sep 2024 15:03:00 -0400 Subject: [PATCH 4/6] Added generic functions to simplify code --- src/http_server.rs | 4 +- src/http_server/switch_utils.rs | 98 +++++++++++++++++ src/http_server/wol_utils.rs | 181 -------------------------------- src/main.rs | 16 +-- 4 files changed, 109 insertions(+), 190 deletions(-) create mode 100644 src/http_server/switch_utils.rs diff --git a/src/http_server.rs b/src/http_server.rs index 9262c6a..7fc8ed9 100644 --- a/src/http_server.rs +++ b/src/http_server.rs @@ -1,4 +1,5 @@ mod html_responses; +mod switch_utils; mod wol_utils; use crate::utils::{abort_connection, wait_for_connection, write_tcp_buf}; @@ -9,7 +10,8 @@ use esp_backtrace as _; use esp_wifi::wifi::{WifiDevice, WifiStaDevice}; use heapless::FnvIndexMap; use html_responses::{HTML_HEADER, HTML_MENU, HTML_TAIL}; -use wol_utils::{switch_command, wol_command}; +use switch_utils::switch_command; +use wol_utils::wol_command; /// The HTTP headers for the response. const HTTP_HEADERS: &[u8] = diff --git a/src/http_server/switch_utils.rs b/src/http_server/switch_utils.rs new file mode 100644 index 0000000..8a7afb8 --- /dev/null +++ b/src/http_server/switch_utils.rs @@ -0,0 +1,98 @@ +use crate::pins::*; +use core::cell::RefCell; +use embassy_sync::blocking_mutex::{raw::CriticalSectionRawMutex, Mutex}; +use embassy_time::{Duration, Timer}; +use esp_hal::gpio::{InputPin, Level, OutputOpenDrain, OutputPin}; + +/// Triggers a GPIO pin based on the provided pin number. +pub async fn switch_command(pin_str: &str) -> Result<(), ()> { + // Parse the pin number as a u8 + let pin = match pin_str.parse::() { + Ok(v) => v, + Err(_) => { + log::error!("Switch | Error parsing pin number"); + return Err(()); + } + }; + + // Toggle the pin based on the number + let result = match pin { + 2 => toggle_pin(&GPIO2, false).await, + 3 => toggle_pin(&GPIO3, false).await, + 4 => toggle_pin(&GPIO4, false).await, + 5 => toggle_pin(&GPIO5, false).await, + 6 => toggle_pin(&GPIO6, false).await, + 7 => toggle_pin(&GPIO7, false).await, + 8 => toggle_pin(&GPIO8, false).await, + 9 => toggle_pin(&GPIO9, false).await, + _ => { + log::warn!("Switch | Invalid pin number"); + return Err(()); + } + }; + + // Check if the pin was toggled successfully + if result.is_err() { + log::error!("Switch | Error toggling pin GPIO{}", pin_str); + return Err(()); + } + + log::info!("SWITCH | Triggered pin GPIO{}", pin_str); + Ok(()) +} + +/// Toggle a GPIO pin behind a Mutex and a RefCell. +/// This function will toggle the pin for 500ms, then toggle it back. +/// The parameter `toggle_high` determines how the pin will be toggled: +/// - `true`: High -> 500ms -> Low +/// - `false`: Low -> 500ms -> High +pub async fn toggle_pin( + gpio: &Mutex>>>, + toggle_high: bool, +) -> Result<(), ()> +where + T: InputPin + OutputPin, +{ + let level_0; + let level_1; + + if toggle_high { + level_0 = Level::High; + level_1 = Level::Low; + } else { + level_0 = Level::Low; + level_1 = Level::High; + } + + set_pin(gpio, level_0)?; + Timer::after(Duration::from_millis(500)).await; + set_pin(gpio, level_1)?; + + Ok(()) +} + +/// Sets a GPIO pin behind a Mutex and a RefCell to the provided level. +pub fn set_pin( + gpio: &Mutex>>>, + level: Level, +) -> Result<(), ()> +where + T: InputPin + OutputPin, +{ + let mut triggered = false; + + gpio.lock(|pin_locked| { + if let Ok(mut pin_option) = pin_locked.try_borrow_mut() { + if let Some(pin) = pin_option.as_mut() { + pin.set_level(level); + triggered = true; + } + } + }); + + if !triggered { + return Err(()); + } + + Ok(()) +} diff --git a/src/http_server/wol_utils.rs b/src/http_server/wol_utils.rs index d459f59..a6cb289 100644 --- a/src/http_server/wol_utils.rs +++ b/src/http_server/wol_utils.rs @@ -1,4 +1,3 @@ -use crate::pins::*; use crate::utils::{convert_mac_address, parse_ip_address}; use embassy_net::{ udp::{PacketMetadata, UdpSocket}, @@ -17,186 +16,6 @@ const WOL_BROADCAST_ADDR: &str = env!("WOL_BROADCAST_ADDR"); /// The fallback broadcast address to send the WOL packet to. const WOL_BROADCAST_ADDR_FALLBACK: IpAddress = IpAddress::v4(255, 255, 255, 255); -/// Triggers a GPIO pin set as an open drain -pub async fn switch_command(pin_str: &str) -> Result<(), ()> { - // Parse the pin number as a u8 - let pin = match pin_str.parse::() { - Ok(v) => v, - Err(_) => { - log::error!("Switch | Error parsing pin number"); - return Err(()); - } - }; - - let mut triggered = false; - match pin { - 2 => { - GPIO2.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO2.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 3 => { - GPIO3.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO3.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 4 => { - GPIO4.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO4.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 5 => { - GPIO5.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO5.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 6 => { - GPIO6.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO6.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 7 => { - GPIO7.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO7.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 8 => { - GPIO8.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO8.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - 9 => { - GPIO9.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - Timer::after(Duration::from_millis(500)).await; - GPIO9.lock(|x| { - if let Some(v) = x.borrow_mut().as_mut() { - v.toggle(); - triggered = true; - } else { - triggered = false; - } - }); - } - _ => { - log::error!("Switch | Invalid pin number"); - return Err(()); - } - } - - if !triggered { - log::error!("Switch | Error toggling pin GPIO{}", pin_str); - return Err(()); - } - - log::info!("SWITCH | Triggered pin GPIO{}", pin_str); - Ok(()) -} - /// Send a Wake-on-LAN command to the specified MAC address. pub async fn wol_command( stack: &'static Stack>, diff --git a/src/main.rs b/src/main.rs index 1e2bd61..857c6f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,14 +67,14 @@ async fn main(spawner: Spawner) { let mut rng = Rng::new(peripherals.RNG); // Initialize GPIO pins - let gpio2 = OutputOpenDrain::new(io.pins.gpio2, Level::Low, Pull::Up); - let gpio3 = OutputOpenDrain::new(io.pins.gpio3, Level::Low, Pull::Up); - let gpio4 = OutputOpenDrain::new(io.pins.gpio4, Level::Low, Pull::Up); - let gpio5 = OutputOpenDrain::new(io.pins.gpio5, Level::Low, Pull::Up); - let gpio6 = OutputOpenDrain::new(io.pins.gpio6, Level::Low, Pull::Up); - let gpio7 = OutputOpenDrain::new(io.pins.gpio7, Level::Low, Pull::Up); - let gpio8 = OutputOpenDrain::new(io.pins.gpio8, Level::Low, Pull::Up); - let gpio9 = OutputOpenDrain::new(io.pins.gpio9, Level::Low, Pull::Up); + let gpio2 = OutputOpenDrain::new(io.pins.gpio2, Level::High, Pull::Up); + let gpio3 = OutputOpenDrain::new(io.pins.gpio3, Level::High, Pull::Up); + let gpio4 = OutputOpenDrain::new(io.pins.gpio4, Level::High, Pull::Up); + let gpio5 = OutputOpenDrain::new(io.pins.gpio5, Level::High, Pull::Up); + let gpio6 = OutputOpenDrain::new(io.pins.gpio6, Level::High, Pull::Up); + let gpio7 = OutputOpenDrain::new(io.pins.gpio7, Level::High, Pull::Up); + let gpio8 = OutputOpenDrain::new(io.pins.gpio8, Level::High, Pull::Up); + let gpio9 = OutputOpenDrain::new(io.pins.gpio9, Level::High, Pull::Up); GPIO2.lock(|x| x.borrow_mut().replace(gpio2)); GPIO3.lock(|x| x.borrow_mut().replace(gpio3)); GPIO4.lock(|x| x.borrow_mut().replace(gpio4)); From 0e838da01372daa9019e503c3238d95d64091c3b Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Mon, 16 Sep 2024 14:07:22 -0400 Subject: [PATCH 5/6] Added warning about GPIO voltage --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b7f779..4c5a155 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,8 @@ Set the following environment variables. These variables are used to configure t **Switch Configuration** -- `SWITCH_ENABLE`: A flag to enable or disable the Switch feature of the HTTP server. This uses the ESP32 as a computer power switch. Set to "true" or "1" to enable. **If you use this as a power switch, make sure to properly configure the GPIO pins as Pull Up or Pull Down in the `./src/main.rs` file.** +- `SWITCH_ENABLE`: A flag to enable or disable the Switch feature of the HTTP server. This uses the ESP32 as a power switch. Set to "true" or "1" to enable. + - **If you use the Wakesp as a power switch, make sure to properly configure the GPIO pins as Pull Up or Pull Down in the `./src/main.rs` file depending on which device you want to switch ON and OFF. Make sure the pin on which you connect the Wakesp GPIO pin has a voltage of 3.3V.** Here is an example of setting these variables: From a29468c912ebc5d7f5884bdd3deea64586d253cb Mon Sep 17 00:00:00 2001 From: etiennecollin Date: Tue, 17 Sep 2024 01:18:51 -0400 Subject: [PATCH 6/6] Added shared ground warning --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c5a155..8935b90 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,11 @@ Set the following environment variables. These variables are used to configure t **Switch Configuration** - `SWITCH_ENABLE`: A flag to enable or disable the Switch feature of the HTTP server. This uses the ESP32 as a power switch. Set to "true" or "1" to enable. - - **If you use the Wakesp as a power switch, make sure to properly configure the GPIO pins as Pull Up or Pull Down in the `./src/main.rs` file depending on which device you want to switch ON and OFF. Make sure the pin on which you connect the Wakesp GPIO pin has a voltage of 3.3V.** + - **Make sure to properly configure the GPIO pins as Pull Up or Pull Down in the `./src/main.rs` file depending on which device you want to switch ON and OFF.** + - Computer power switches often need a Pull Up configuration. + - **Make sure the pins on which you connect the Wakesp GPIO pins have a voltage of 3.3V. Use a level shifter if needed.** + - **Make sure the Wakesp and the devices it is connected to share the same ground.** + - **If you do not follow these last 3 points, the Wakesp and/or the devices it is connected to could be permanently damaged.** Here is an example of setting these variables: