203 lines
6.4 KiB
Rust
203 lines
6.4 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
#![feature(type_alias_impl_trait)]
|
|
|
|
use embassy_executor::Spawner;
|
|
use embassy_net::tcp::TcpSocket;
|
|
use embassy_net::{Config, Ipv4Address, Stack, StackResources};
|
|
use esp_hal::{self, IO};
|
|
|
|
use const_format::formatcp;
|
|
use embassy_time::{Duration, Timer};
|
|
use embedded_hal_async::digital::Wait;
|
|
use esp_backtrace as _;
|
|
use esp_hal::clock::ClockControl;
|
|
use esp_hal::gpio::{AnyPin, Input, PullUp};
|
|
use esp_hal::Rng;
|
|
use esp_hal::{embassy, peripherals::Peripherals, prelude::*, timer::TimerGroup};
|
|
use esp_println::println;
|
|
use esp_wifi::wifi::{ClientConfiguration, Configuration};
|
|
use esp_wifi::wifi::{WifiController, WifiDevice, WifiEvent, WifiStaDevice, WifiState};
|
|
use esp_wifi::{initialize, EspWifiInitFor};
|
|
use static_cell::make_static;
|
|
|
|
const SSID: &str = env!("SSID");
|
|
const PASSWORD: &str = env!("PASSWORD");
|
|
|
|
#[main]
|
|
async fn main(spawner: Spawner) {
|
|
#[cfg(feature = "log")]
|
|
esp_println::logger::init_logger(log::LevelFilter::Info);
|
|
|
|
let peripherals = Peripherals::take();
|
|
|
|
let system = peripherals.SYSTEM.split();
|
|
let clocks = ClockControl::max(system.clock_control).freeze();
|
|
|
|
#[cfg(target_arch = "xtensa")]
|
|
let timer = esp_hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks).timer0;
|
|
#[cfg(target_arch = "riscv32")]
|
|
let timer = esp_hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0;
|
|
let init = initialize(
|
|
EspWifiInitFor::Wifi,
|
|
timer,
|
|
Rng::new(peripherals.RNG),
|
|
system.radio_clock_control,
|
|
&clocks,
|
|
)
|
|
.unwrap();
|
|
|
|
let wifi = peripherals.WIFI;
|
|
let (wifi_interface, controller) =
|
|
esp_wifi::wifi::new_with_mode(&init, wifi, WifiStaDevice).unwrap();
|
|
|
|
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
|
embassy::init(&clocks, timer_group0);
|
|
|
|
let config = Config::dhcpv4(Default::default());
|
|
|
|
let seed = 1234; // very random, very secure seed
|
|
|
|
// Init network stack
|
|
let stack = &*make_static!(Stack::new(
|
|
wifi_interface,
|
|
config,
|
|
make_static!(StackResources::<3>::new()),
|
|
seed
|
|
));
|
|
|
|
spawner.spawn(connection(controller)).ok();
|
|
spawner.spawn(net_task(&stack)).ok();
|
|
|
|
loop {
|
|
if stack.is_link_up() {
|
|
break;
|
|
}
|
|
Timer::after(Duration::from_millis(500)).await;
|
|
}
|
|
|
|
println!("Waiting to get IP address...");
|
|
loop {
|
|
if let Some(config) = stack.config_v4() {
|
|
println!("Got IP: {}", config.address);
|
|
break;
|
|
}
|
|
Timer::after(Duration::from_millis(500)).await;
|
|
}
|
|
|
|
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
|
let button = io.pins.gpio12.into_pull_up_input();
|
|
println!("Spawning button task");
|
|
spawner.must_spawn(button_task(button.into(), stack));
|
|
}
|
|
|
|
async fn ring(stack: &'static Stack<WifiDevice<'static, WifiStaDevice>>) -> Result<(), &str> {
|
|
let mut rx_buffer = [0; 4096];
|
|
let mut tx_buffer = [0; 4096];
|
|
|
|
Timer::after(Duration::from_millis(1_000)).await;
|
|
|
|
let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
|
|
|
|
socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
|
|
|
|
let remote_endpoint = (Ipv4Address::new(104, 20, 43, 236), 80);
|
|
println!("connecting...");
|
|
let r = socket.connect(remote_endpoint).await;
|
|
if let Err(e) = r {
|
|
println!("connect error: {:?}", e);
|
|
return Err("connect error");
|
|
}
|
|
|
|
const JSON: &'static str = "{
|
|
\"token\": \"ahgvt9acdx5sowxfobadt9cmpqhrzp\",
|
|
\"user\": \"ud2btptjwvy92xi8y77tfurfew6z7a\",
|
|
\"message\": \"DOOR BELL!!!\"
|
|
}";
|
|
const JSON_LEN: usize = JSON.len();
|
|
|
|
println!("connected!");
|
|
let mut buf = [0; 1024];
|
|
loop {
|
|
use embedded_io_async::Write;
|
|
let req = formatcp!("POST /1/messages.json HTTP/1.0\r\nHost: api.pushover.net\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}\r\n\r\n", JSON_LEN, JSON);
|
|
println!("{}", req);
|
|
let r = socket.write_all(req.as_bytes()).await;
|
|
if let Err(e) = r {
|
|
println!("write error: {:?}", e);
|
|
break;
|
|
}
|
|
let n = match socket.read(&mut buf).await {
|
|
Ok(0) => {
|
|
println!("read EOF");
|
|
break;
|
|
}
|
|
Ok(n) => n,
|
|
Err(e) => {
|
|
println!("read error: {:?}", e);
|
|
break;
|
|
}
|
|
};
|
|
println!("{}", core::str::from_utf8(&buf[..n]).unwrap());
|
|
}
|
|
Timer::after(Duration::from_millis(5000)).await;
|
|
Ok(())
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
async fn button_task(
|
|
mut button: AnyPin<Input<PullUp>>,
|
|
stack: &'static Stack<WifiDevice<'static, WifiStaDevice>>,
|
|
) {
|
|
loop {
|
|
button.wait_for_falling_edge().await.unwrap();
|
|
Timer::after_millis(10).await;
|
|
if button.is_low().unwrap() {
|
|
println!("Button pressed");
|
|
ring(stack)
|
|
.await
|
|
.unwrap_or_else(|e| println!("ring error: {}", e));
|
|
}
|
|
}
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
async fn connection(mut controller: WifiController<'static>) {
|
|
println!("start connection task");
|
|
println!("Device capabilities: {:?}", controller.get_capabilities());
|
|
loop {
|
|
match esp_wifi::wifi::get_wifi_state() {
|
|
WifiState::StaConnected => {
|
|
// wait until we're no longer connected
|
|
controller.wait_for_event(WifiEvent::StaDisconnected).await;
|
|
Timer::after(Duration::from_millis(5000)).await
|
|
}
|
|
_ => {}
|
|
}
|
|
if !matches!(controller.is_started(), Ok(true)) {
|
|
let client_config = Configuration::Client(ClientConfiguration {
|
|
ssid: SSID.try_into().unwrap(),
|
|
password: PASSWORD.try_into().unwrap(),
|
|
..Default::default()
|
|
});
|
|
controller.set_configuration(&client_config).unwrap();
|
|
println!("Starting wifi");
|
|
controller.start().await.unwrap();
|
|
println!("Wifi started!");
|
|
}
|
|
println!("About to connect...");
|
|
|
|
match controller.connect().await {
|
|
Ok(_) => println!("Wifi connected!"),
|
|
Err(e) => {
|
|
println!("Failed to connect to wifi: {e:?}");
|
|
Timer::after(Duration::from_millis(5000)).await
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[embassy_executor::task]
|
|
async fn net_task(stack: &'static Stack<WifiDevice<'static, WifiStaDevice>>) {
|
|
stack.run().await
|
|
}
|