|
|
@ -6,13 +6,18 @@ |
|
|
holding buffers for the duration of a data transfer."
|
|
|
holding buffers for the duration of a data transfer."
|
|
|
)]
|
|
|
)]
|
|
|
|
|
|
|
|
|
use defmt::info;
|
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
|
|
extern crate alloc;
|
|
|
|
|
|
|
|
|
|
|
|
use defmt::{error, info};
|
|
|
use embassy_executor::Spawner;
|
|
|
use embassy_executor::Spawner;
|
|
|
|
|
|
use embassy_net::{DhcpConfig, Stack};
|
|
|
use embassy_time::{Delay, Duration, Timer};
|
|
|
use embassy_time::{Delay, Duration, Timer};
|
|
|
use embedded_graphics::primitives::{Line, Polyline, PrimitiveStyle};
|
|
|
use embedded_graphics::primitives::{Line, Polyline, PrimitiveStyle};
|
|
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
|
|
use embedded_hal_bus::spi::ExclusiveDevice;
|
|
|
use esp_hal::clock::CpuClock;
|
|
|
use esp_hal::clock::CpuClock;
|
|
|
use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull};
|
|
|
use esp_hal::gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull};
|
|
|
|
|
|
use esp_hal::rng::Rng;
|
|
|
use esp_hal::timer::timg::TimerGroup;
|
|
|
use esp_hal::timer::timg::TimerGroup;
|
|
|
use esp_println as _;
|
|
|
use esp_println as _;
|
|
|
|
|
|
|
|
|
@ -33,8 +38,44 @@ use embedded_graphics::mono_font::ascii::FONT_10X20; |
|
|
use embedded_graphics::prelude::*;
|
|
|
use embedded_graphics::prelude::*;
|
|
|
use embedded_graphics::text::{Baseline, Text};
|
|
|
use embedded_graphics::text::{Baseline, Text};
|
|
|
|
|
|
|
|
|
|
|
|
// wifi
|
|
|
|
|
|
use esp_radio::wifi::{ClientConfig, Config, ModeConfig, ScanConfig, WifiController, WifiDevice, WifiEvent};
|
|
|
|
|
|
|
|
|
|
|
|
use embassy_net::{
|
|
|
|
|
|
Runner,
|
|
|
|
|
|
StackResources,
|
|
|
|
|
|
dns::DnsSocket,
|
|
|
|
|
|
tcp::client::{TcpClient, TcpClientState},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// time handling
|
|
|
|
|
|
use jiff::{tz::{self, TimeZone}, Timestamp};
|
|
|
|
|
|
|
|
|
|
|
|
use picojson::{SliceParser, PullParser, Event};
|
|
|
|
|
|
// tls
|
|
|
|
|
|
use reqwless::client::{HttpClient, TlsConfig, TlsVerify};
|
|
|
|
|
|
|
|
|
|
|
|
const WLAN_SSID: &str = env!("WLAN_SSID");
|
|
|
|
|
|
const WLAN_PASS: &str = env!("WLAN_PASS");
|
|
|
|
|
|
|
|
|
|
|
|
// (a little clumsy to have to specify the byte length here, but currently no way around that..)
|
|
|
|
|
|
const LETSENCRYPT_ROOT_PEM: &'static [u8; 1566] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/letsencrypt-root.pem"));
|
|
|
|
|
|
|
|
|
|
|
|
static TZ_EUROPE_BERLIN: TimeZone = tz::include!("/usr/share/zoneinfo/Europe/Berlin");
|
|
|
|
|
|
|
|
|
|
|
|
// from: https://github.com/esp-rs/esp-hal/blob/8281e43ba17f2140dea5e0d7e0cac4a7fa7318f2/examples/wifi/embassy_dhcp/src/main.rs
|
|
|
|
|
|
macro_rules! mk_static {
|
|
|
|
|
|
($t:ty,$val:expr) => {{
|
|
|
|
|
|
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
|
|
|
|
|
|
#[deny(unused_attributes)]
|
|
|
|
|
|
let x = STATIC_CELL.uninit().write(($val));
|
|
|
|
|
|
x
|
|
|
|
|
|
}}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
#[panic_handler]
|
|
|
#[panic_handler]
|
|
|
fn panic(_: &core::panic::PanicInfo) -> ! {
|
|
|
|
|
|
|
|
|
fn panic(pi: &core::panic::PanicInfo) -> ! {
|
|
|
|
|
|
error!("panic: {}", pi);
|
|
|
loop {}
|
|
|
loop {}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -54,12 +95,126 @@ async fn main(spawner: Spawner) -> ! { |
|
|
|
|
|
|
|
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
|
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
|
|
esp_rtos::start(timg0.timer0);
|
|
|
esp_rtos::start(timg0.timer0);
|
|
|
|
|
|
|
|
|
info!("Embassy initialized!");
|
|
|
info!("Embassy initialized!");
|
|
|
|
|
|
|
|
|
// TODO: Spawn some tasks
|
|
|
|
|
|
let _ = spawner;
|
|
|
|
|
|
|
|
|
// wlan setup
|
|
|
|
|
|
let controller = &*mk_static!(esp_radio::Controller<'static>, esp_radio::init().expect("init radio controller"));
|
|
|
|
|
|
let (wifi_controller, interfaces) =
|
|
|
|
|
|
esp_radio::wifi::new(controller, peripherals.WIFI, Config::default()).expect("wifi init");
|
|
|
|
|
|
|
|
|
|
|
|
let wifi_interface = interfaces.sta;
|
|
|
|
|
|
let dhcp_config = embassy_net::Config::dhcpv4(DhcpConfig::default());
|
|
|
|
|
|
|
|
|
|
|
|
let rng = Rng::new();
|
|
|
|
|
|
let net_seed = (rng.random() as u64) << 32 | rng.random() as u64;
|
|
|
|
|
|
|
|
|
|
|
|
let (stack, runner) = embassy_net::new(wifi_interface, dhcp_config, mk_static!(StackResources::<3>, StackResources::<3>::new()), net_seed);
|
|
|
|
|
|
|
|
|
|
|
|
spawner.spawn(connection(wifi_controller)).expect("spawn wifi connection task");
|
|
|
|
|
|
spawner.spawn(net_task(runner)).expect("spawn net task");
|
|
|
|
|
|
|
|
|
|
|
|
wait_for_network_up(stack).await;
|
|
|
|
|
|
|
|
|
|
|
|
let dns = DnsSocket::new(stack);
|
|
|
|
|
|
|
|
|
|
|
|
let tcp_state = TcpClientState::<1, 4096, 4096>::new();
|
|
|
|
|
|
let tcp = TcpClient::new(stack, &tcp_state);
|
|
|
|
|
|
info!("tcp client");
|
|
|
|
|
|
|
|
|
|
|
|
let tls_seed = (rng.random() as u64) << 32 | rng.random() as u64;
|
|
|
|
|
|
let mut tls_tx_buf = [0u8; 4096];
|
|
|
|
|
|
let mut tls_rx_buf = [0u8; 4096];
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: tls verify
|
|
|
|
|
|
let tls_config = TlsConfig::new(tls_seed, &mut tls_rx_buf, &mut tls_tx_buf, TlsVerify::None);
|
|
|
|
|
|
let mut http_client = HttpClient::new_with_tls(&tcp, &dns, tls_config);
|
|
|
|
|
|
info!("http client");
|
|
|
|
|
|
|
|
|
|
|
|
let mut buf = [0u8; 16384];
|
|
|
|
|
|
let http_req = http_client
|
|
|
|
|
|
.request(reqwless::request::Method::GET, "https://e.q0b.de/price?bzn=DE-LU")
|
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
|
|
// reverse proxy e.q0b.de/.* -> https://api.energy-charts.info/$1 with tls1_3 because api.energy-charts.info only does tlsv1.2...
|
|
|
|
|
|
let mut http_req = match http_req {
|
|
|
|
|
|
Ok(r) => r,
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
error!("{}", e);
|
|
|
|
|
|
panic!("failed to make http req");
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let rsp = http_req.send(&mut buf).await.expect("http send");
|
|
|
|
|
|
info!("rsp made");
|
|
|
|
|
|
let res = rsp.body().read_to_end().await.expect("read rsp body");
|
|
|
|
|
|
info!("energy price: {}", str::from_utf8(res).expect("utf8"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// parsing the response
|
|
|
|
|
|
enum ParseNext {
|
|
|
|
|
|
Nothing,
|
|
|
|
|
|
Timestamps,
|
|
|
|
|
|
Prices,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut scratch = [0u8; 128];
|
|
|
|
|
|
let mut parser = SliceParser::with_buffer_from_slice(res, &mut scratch);
|
|
|
|
|
|
|
|
|
|
|
|
// 24 hours * 4 items/hour (15min resolution) = 96 items total per day
|
|
|
|
|
|
const MAX_ITEMS: usize = 96;
|
|
|
|
|
|
let mut timestamps = [0i64; MAX_ITEMS];
|
|
|
|
|
|
let mut timestamps_idx = 0;
|
|
|
|
|
|
let mut prices = [0f32; MAX_ITEMS];
|
|
|
|
|
|
let mut prices_idx = 0;
|
|
|
|
|
|
let mut parse_next = ParseNext::Nothing;
|
|
|
|
|
|
|
|
|
|
|
|
let mut max_price = f32::MIN;
|
|
|
|
|
|
let mut min_price = f32::MAX;
|
|
|
|
|
|
|
|
|
|
|
|
while let Some(ref parse_result) = parser.next() {
|
|
|
|
|
|
match parse_result {
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
// TODO: defmt error printing impl for picojson
|
|
|
|
|
|
error!("json parse error");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(Event::Key(k)) => {
|
|
|
|
|
|
if k.as_str() == "unix_seconds" {
|
|
|
|
|
|
parse_next = ParseNext::Timestamps;
|
|
|
|
|
|
} else if k.as_str() == "price" {
|
|
|
|
|
|
parse_next = ParseNext::Prices;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(Event::Number(n)) => {
|
|
|
|
|
|
match parse_next {
|
|
|
|
|
|
ParseNext::Timestamps => {
|
|
|
|
|
|
if timestamps_idx < MAX_ITEMS {
|
|
|
|
|
|
timestamps[timestamps_idx] = n.as_int().unwrap();
|
|
|
|
|
|
timestamps_idx += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ParseNext::Prices => {
|
|
|
|
|
|
if prices_idx < MAX_ITEMS {
|
|
|
|
|
|
prices[prices_idx] = n.as_f64().unwrap() as f32 / 10.0;
|
|
|
|
|
|
|
|
|
|
|
|
max_price = max_price.max(prices[prices_idx]);
|
|
|
|
|
|
min_price = min_price.min(prices[prices_idx]);
|
|
|
|
|
|
|
|
|
|
|
|
prices_idx += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => error!("got a number, but not in a number parser state"),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Ok(_) => {},
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for i in 0..MAX_ITEMS {
|
|
|
|
|
|
info!("{}: {}", timestamps[i], prices[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// spi display drawing
|
|
|
let spi_bus = Spi::new(
|
|
|
let spi_bus = Spi::new(
|
|
|
peripherals.SPI2,
|
|
|
peripherals.SPI2,
|
|
|
spi::master::Config::default()
|
|
|
spi::master::Config::default()
|
|
|
@ -93,120 +248,30 @@ async fn main(spawner: Spawner) -> ! { |
|
|
epd.update_and_display_frame(&mut spi_dev, display.buffer(), &mut Delay)
|
|
|
epd.update_and_display_frame(&mut spi_dev, display.buffer(), &mut Delay)
|
|
|
.unwrap();
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
let prices = [
|
|
|
|
|
|
124.51,
|
|
|
|
|
|
120.29,
|
|
|
|
|
|
117.14,
|
|
|
|
|
|
115.63,
|
|
|
|
|
|
122.15,
|
|
|
|
|
|
119.4,
|
|
|
|
|
|
119.33,
|
|
|
|
|
|
117.12,
|
|
|
|
|
|
120.92,
|
|
|
|
|
|
118.14,
|
|
|
|
|
|
115.3,
|
|
|
|
|
|
115.01,
|
|
|
|
|
|
116.5,
|
|
|
|
|
|
119.49,
|
|
|
|
|
|
117.0,
|
|
|
|
|
|
118.34,
|
|
|
|
|
|
117.67,
|
|
|
|
|
|
118.73,
|
|
|
|
|
|
120.93,
|
|
|
|
|
|
123.66,
|
|
|
|
|
|
119.8,
|
|
|
|
|
|
129.0,
|
|
|
|
|
|
143.99,
|
|
|
|
|
|
153.06,
|
|
|
|
|
|
152.2,
|
|
|
|
|
|
168.99,
|
|
|
|
|
|
179.1,
|
|
|
|
|
|
190.23,
|
|
|
|
|
|
203.74,
|
|
|
|
|
|
191.36,
|
|
|
|
|
|
170.92,
|
|
|
|
|
|
139.56,
|
|
|
|
|
|
194.19,
|
|
|
|
|
|
151.4,
|
|
|
|
|
|
136.77,
|
|
|
|
|
|
107.87,
|
|
|
|
|
|
136.41,
|
|
|
|
|
|
122.21,
|
|
|
|
|
|
109.38,
|
|
|
|
|
|
88.01,
|
|
|
|
|
|
101.21,
|
|
|
|
|
|
90.13,
|
|
|
|
|
|
86.53,
|
|
|
|
|
|
71.17,
|
|
|
|
|
|
85.31,
|
|
|
|
|
|
77.93,
|
|
|
|
|
|
68.83,
|
|
|
|
|
|
59.17,
|
|
|
|
|
|
70.74,
|
|
|
|
|
|
64.99,
|
|
|
|
|
|
61.01,
|
|
|
|
|
|
56.54,
|
|
|
|
|
|
61.21,
|
|
|
|
|
|
59.19,
|
|
|
|
|
|
57.9,
|
|
|
|
|
|
60.1,
|
|
|
|
|
|
58.27,
|
|
|
|
|
|
67.62,
|
|
|
|
|
|
82.3,
|
|
|
|
|
|
88.11,
|
|
|
|
|
|
78.83,
|
|
|
|
|
|
91.99,
|
|
|
|
|
|
95.32,
|
|
|
|
|
|
103.15,
|
|
|
|
|
|
90.64,
|
|
|
|
|
|
100.02,
|
|
|
|
|
|
100.98,
|
|
|
|
|
|
120.69,
|
|
|
|
|
|
105.61,
|
|
|
|
|
|
130.77,
|
|
|
|
|
|
146.59,
|
|
|
|
|
|
173.23,
|
|
|
|
|
|
145.81,
|
|
|
|
|
|
159.0,
|
|
|
|
|
|
163.46,
|
|
|
|
|
|
167.46,
|
|
|
|
|
|
192.98,
|
|
|
|
|
|
177.61,
|
|
|
|
|
|
158.25,
|
|
|
|
|
|
144.14,
|
|
|
|
|
|
174.9,
|
|
|
|
|
|
150.14,
|
|
|
|
|
|
127.52,
|
|
|
|
|
|
119.0,
|
|
|
|
|
|
124.13,
|
|
|
|
|
|
122.5,
|
|
|
|
|
|
119.78,
|
|
|
|
|
|
109.57,
|
|
|
|
|
|
123.1,
|
|
|
|
|
|
117.9,
|
|
|
|
|
|
117.59,
|
|
|
|
|
|
108.05,
|
|
|
|
|
|
113.65,
|
|
|
|
|
|
106.89,
|
|
|
|
|
|
105.25,
|
|
|
|
|
|
98.26,
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
let mut points = [Point::new(0, 0); 96 /* TODO: same size as prices? or assume+validate/truncate first 96? */];
|
|
|
|
|
|
let mut foo = [0u8; 2];
|
|
|
|
|
|
|
|
|
// draw values for min/max
|
|
|
|
|
|
draw_text(&mut display, &format!("{}", max_price), 10, 20);
|
|
|
|
|
|
draw_text(&mut display, &format!("{}", min_price), 10, 260);
|
|
|
|
|
|
|
|
|
|
|
|
// current date, probably from the first timestamp (i.e. we assume we get things starting from 00:00)
|
|
|
|
|
|
let ts = Timestamp::from_second(timestamps[0]).unwrap().to_zoned(TZ_EUROPE_BERLIN.clone());
|
|
|
|
|
|
draw_text(&mut display, &format!("{}", ts.date()), 180, 10);
|
|
|
|
|
|
|
|
|
|
|
|
// some padding for the min/max
|
|
|
|
|
|
max_price *= 1.1;
|
|
|
|
|
|
min_price *= 1.1;
|
|
|
|
|
|
|
|
|
|
|
|
let mut points = [Point::new(0, 0); MAX_ITEMS];
|
|
|
for (i, pr) in prices.iter().enumerate() {
|
|
|
for (i, pr) in prices.iter().enumerate() {
|
|
|
points[i] = Point::new(i as i32 * 4, 300 - *pr as i32);
|
|
|
|
|
|
|
|
|
|
|
|
if i % 18 == 0 {
|
|
|
|
|
|
Line::new(Point::new(i as i32 *4, 300), Point::new(i as i32 * 4, 290))
|
|
|
|
|
|
.into_styled(PrimitiveStyle::with_stroke(Color::Black, 5))
|
|
|
|
|
|
.draw(&mut display)
|
|
|
|
|
|
.expect("draw x-axis tick");
|
|
|
|
|
|
|
|
|
|
|
|
// no proper write/format library..
|
|
|
|
|
|
foo[0] = b'0' + (i / 10) as u8;
|
|
|
|
|
|
foo[1] = b'0' + (i % 10) as u8;
|
|
|
|
|
|
draw_text(&mut display, str::from_utf8(&foo[..]).unwrap(), i as i32 * 4, 280);
|
|
|
|
|
|
|
|
|
// fancyer calculations
|
|
|
|
|
|
// scale from price range price_min..price_max to pixel coordinates 270..0
|
|
|
|
|
|
points[i] = Point::new(i as i32 * 4, ((max_price - *pr) / (max_price - min_price) * 270.0) as i32);
|
|
|
|
|
|
|
|
|
|
|
|
let ts = Timestamp::from_second(timestamps[i]).expect("timestamp");
|
|
|
|
|
|
let ts_tz = ts.to_zoned(TZ_EUROPE_BERLIN.clone());
|
|
|
|
|
|
let hour = ts_tz.hour();
|
|
|
|
|
|
|
|
|
|
|
|
if hour != 0 && hour % 3 == 0 && ts_tz.minute() == 0 {
|
|
|
|
|
|
draw_text(&mut display, &format!("{}", hour), i as i32 * 4, 280);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
let line_style = PrimitiveStyle::with_stroke(Color::Black, 3);
|
|
|
let line_style = PrimitiveStyle::with_stroke(Color::Black, 3);
|
|
|
@ -246,10 +311,77 @@ fn draw_text(display: &mut Display4in2, text: &str, x: i32, y: i32) { |
|
|
// * rtc initialization, and/or NTP query, to print times.
|
|
|
// * rtc initialization, and/or NTP query, to print times.
|
|
|
// - maybe we can just convert the time steps from the returned data set, and e.g. do x axis ticks on multiples of 3hours from that
|
|
|
// - maybe we can just convert the time steps from the returned data set, and e.g. do x axis ticks on multiples of 3hours from that
|
|
|
// * wifi
|
|
|
// * wifi
|
|
|
// * tls
|
|
|
|
|
|
// * json parser
|
|
|
|
|
|
|
|
|
// * tls: reqless, esp-mbedtls
|
|
|
|
|
|
// * json parser: https://lib.rs/crates/picojson maybe?
|
|
|
// => fetch data from https://api.energy-charts.info/price?bzn=DE-LU
|
|
|
// => fetch data from https://api.energy-charts.info/price?bzn=DE-LU
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// ## drawing prettier
|
|
|
|
|
|
// * chrono: timestamp -> datetime<utc> -> .hours() % 3 == 0, then x-axis tick
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async fn wait_for_network_up(stack: Stack<'_>) {
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if stack.is_link_up() {
|
|
|
|
|
|
info!("network link up");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
Timer::after(Duration::from_millis(500)).await;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
info!("Waiting to get IP address...");
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if let Some(config) = stack.config_v4() {
|
|
|
|
|
|
info!("Got IP: {}", config.address);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
Timer::after(Duration::from_millis(500)).await;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// from: https://github.com/esp-rs/esp-hal/blob/8281e43ba17f2140dea5e0d7e0cac4a7fa7318f2/examples/wifi/embassy_dhcp/src/main.rs
|
|
|
|
|
|
#[embassy_executor::task]
|
|
|
|
|
|
async fn connection(mut controller: WifiController<'static>) {
|
|
|
|
|
|
info!("start connection task");
|
|
|
|
|
|
loop {
|
|
|
|
|
|
if matches!(controller.is_connected(), Ok(true)) {
|
|
|
|
|
|
// 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 wlan_cfg = ModeConfig::Client(
|
|
|
|
|
|
ClientConfig::default()
|
|
|
|
|
|
.with_ssid(WLAN_SSID.into())
|
|
|
|
|
|
.with_password(WLAN_PASS.into())
|
|
|
|
|
|
);
|
|
|
|
|
|
controller.set_config(&wlan_cfg).unwrap();
|
|
|
|
|
|
info!("Starting wifi");
|
|
|
|
|
|
controller.start_async().await.unwrap();
|
|
|
|
|
|
info!("Wifi started!");
|
|
|
|
|
|
|
|
|
|
|
|
info!("Scan");
|
|
|
|
|
|
let scan_config = ScanConfig::default().with_max(10);
|
|
|
|
|
|
let result = controller
|
|
|
|
|
|
.scan_with_config_async(scan_config)
|
|
|
|
|
|
.await
|
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
for ap in result {
|
|
|
|
|
|
info!("{:?}", ap);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
info!("About to connect...");
|
|
|
|
|
|
|
|
|
|
|
|
match controller.connect_async().await {
|
|
|
|
|
|
Ok(_) => info!("Wifi connected!"),
|
|
|
|
|
|
Err(e) => {
|
|
|
|
|
|
info!("Failed to connect to wifi: {:?}", e);
|
|
|
|
|
|
Timer::after(Duration::from_millis(5000)).await
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[embassy_executor::task]
|
|
|
|
|
|
async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) {
|
|
|
|
|
|
runner.run().await
|
|
|
|
|
|
}
|