diff --git a/.gitignore b/.gitignore index 1fb49f9..bf067c8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /.embuild /target /Cargo.lock -wifi-creds.txt \ No newline at end of file +wifi-creds.txt +untis-creds.txt \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index a8145b9..31afd6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,11 @@ epd-waveshare = "0.6.0" embedded-graphics = "0.8.1" embedded-hal = "1.0.0" heapless = "0.8" +esp-idf-sys = "0.36.1" +anyhow = "1.0.99" +embedded-svc = "0.28.1" +untis = {path = "../untis-test/untis-rs"} +chrono = "0.4.41" # --- Optional Embassy Integration --- # esp-idf-svc = { version = "0.51", features = ["critical-section", "embassy-time-driver", "embassy-sync"] } diff --git a/src/main.rs b/src/main.rs index 4ffb3d9..72fe2c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,31 @@ +use std::borrow::Cow; use std::str::FromStr; -use embedded_graphics::{mono_font::MonoTextStyleBuilder, prelude::Point, Drawable, text::{Baseline, Text, TextStyleBuilder}}; +use chrono::{Datelike, Days, NaiveTime}; +use embedded_graphics::{ + mono_font::MonoTextStyleBuilder, + prelude::Point, + text::{Baseline, Text, TextStyleBuilder}, + Drawable, +}; use epd_waveshare::{color::Color, epd7in5_v2::Epd7in5, prelude::WaveshareDisplay}; -use esp_idf_hal::{delay::{Delay, Ets}, gpio::{Gpio19, PinDriver}, spi::{config, Spi, SpiDriver, SpiDriverConfig}}; -use esp_idf_svc::{eventloop::EspSystemEventLoop, hal::{prelude::*, spi::SpiDeviceDriver}, nvs::EspDefaultNvsPartition, wifi::Configuration}; -use esp_idf_svc::wifi::{EspWifi, BlockingWifi}; -use embedded_hal::delay::DelayNs; +use esp_idf_hal::{ + delay::{Ets}, + gpio::{Gpio19, PinDriver}, + spi::{config, SpiDriverConfig}, +}; +use esp_idf_svc::http::client::{Configuration as HttpConfig, EspHttpConnection}; +use esp_idf_svc::wifi::{BlockingWifi, EspWifi}; +use esp_idf_svc::{ + eventloop::EspSystemEventLoop, + hal::{prelude::*, spi::SpiDeviceDriver}, + nvs::EspDefaultNvsPartition, + wifi::Configuration, +}; +use untis::{Date, Lesson}; -//static mut display: epd_waveshare::epd7in5_v2::Display7in5 = epd_waveshare::epd7in5_v2::Display7in5::default(); - -//static FRAMEBUF: [u8; 48000] = [63; 48000]; -fn main() { +fn main() -> anyhow::Result<()> { // It is necessary to call this function once. Otherwise some patches to the runtime // implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71 esp_idf_svc::sys::link_patches(); @@ -29,79 +43,80 @@ fn main() { let mosi = peripherals.pins.gpio23; // y let miso = peripherals.pins.gpio19; // aka. dc - let dc = PinDriver::output(miso).unwrap(); - log::info!("Initialized pins"); - let config = config::Config::new(); let mut spi = SpiDeviceDriver::new_single( peripherals.spi2, // 2 oder 3? clk, - mosi, + mosi, Option::::None, - Some(cs), + Some(cs), &SpiDriverConfig::default(), - &config - ).unwrap(); + &config, + ) + .unwrap(); log::info!("Initialized spi interface"); // Allocating on the stack makes the chip crash. We gotta put it on the heap - let mut display = Box::new(epd_waveshare::epd7in5_v2::Display7in5::default()); + let mut display = Box::new(epd_waveshare::epd7in5_v2::Display7in5::default()); display.set_rotation(epd_waveshare::prelude::DisplayRotation::Rotate0); let mut delay = Ets; let mut epd7in5 = Epd7in5::new(&mut spi, busy, dc, rst, &mut delay, None).unwrap(); - log::info!("Created epd object"); - // Create a file called wifi-creds.txt and write SSID and password into it separated by a line break let mut creds = include_str!("../wifi-creds.txt").split('\n'); - let ssid: heapless::String<32> = heapless::String::<32>::from_str(creds.next().unwrap()).unwrap(); - let password: heapless::String<64> = heapless::String::<64>::from_str(creds.next().unwrap()).unwrap(); + let ssid: heapless::String<32> = + heapless::String::<32>::from_str(creds.next().unwrap()).unwrap(); + let password: heapless::String<64> = + heapless::String::<64>::from_str(creds.next().unwrap()).unwrap(); // Connecting to wifi let sysloop = EspSystemEventLoop::take().unwrap(); let nvs = EspDefaultNvsPartition::take().unwrap(); - let mut wifi = - BlockingWifi::wrap( - EspWifi::new(peripherals.modem, sysloop.clone(), Some(nvs)).unwrap(), sysloop.clone()).unwrap(); - wifi.set_configuration(&Configuration::Client(esp_idf_svc::wifi::ClientConfiguration { - ssid, - password, - auth_method: esp_idf_svc::wifi::AuthMethod::WPA2WPA3Personal, - ..Default::default() - }) - ).unwrap(); - + let mut wifi = BlockingWifi::wrap( + EspWifi::new(peripherals.modem, sysloop.clone(), Some(nvs)).unwrap(), + sysloop.clone(), + ) + .unwrap(); + wifi.set_configuration(&Configuration::Client( + esp_idf_svc::wifi::ClientConfiguration { + ssid, + password, + auth_method: esp_idf_svc::wifi::AuthMethod::WPA2WPA3Personal, + ..Default::default() + }, + )) + .unwrap(); wifi.start().unwrap(); wifi.connect().unwrap(); wifi.wait_netif_up().unwrap(); - while !wifi.is_connected().unwrap(){ - let config = wifi.get_configuration().unwrap(); - println!("Waiting for station {:?}", config); - } - + while !wifi.is_connected().unwrap() {} + println!("Connected to wifi"); + let ip_info = wifi.wifi().sta_netif().get_ip_info().unwrap(); - + let httpconnection = EspHttpConnection::new(&HttpConfig { + use_global_ca_store: true, + crt_bundle_attach: Some(esp_idf_sys::esp_crt_bundle_attach), + ..Default::default() + })?; - draw_text(&mut display, &format!("{:#?}", ip_info), 5, 5); - log::info!("Draw text done"); + let tt = fetch_timetable(httpconnection); + draw_text(&mut display, &tt[3][5].clone().unwrap().subjects.first().as_ref().unwrap().name, 5, 5); + epd7in5.update_and_display_frame(&mut spi, &*display.buffer(), &mut delay)?; + epd7in5.sleep(&mut spi, &mut delay)?; + log::info!("Completed"); - let res = epd7in5.update_and_display_frame(&mut spi, &*display.buffer(), &mut delay); - if let Err(e) = res{ - log::info!("{}", e); - } - epd7in5.sleep(&mut spi, &mut delay).unwrap(); - + Ok(()) } fn draw_text(display: &mut epd_waveshare::epd7in5_v2::Display7in5, text: &str, x: i32, y: i32) { @@ -113,6 +128,60 @@ fn draw_text(display: &mut epd_waveshare::epd7in5_v2::Display7in5, text: &str, x let text_style = TextStyleBuilder::new().baseline(Baseline::Top).build(); - // The problem: let _ = Text::with_text_style(text, Point::new(x, y), style, text_style).draw(display); } + +type Timetable = [[Option;8]; 5]; + +fn transform_lessons(lessons: Vec) -> Box{ + let lookup: [NaiveTime; 8] = [ + (NaiveTime::from_hms_opt(8, 45, 0).unwrap()), + (NaiveTime::from_hms_opt(9, 35, 0).unwrap()), + (NaiveTime::from_hms_opt(10, 40, 0).unwrap()), + (NaiveTime::from_hms_opt(11, 30, 0).unwrap()), + (NaiveTime::from_hms_opt(12, 40, 0).unwrap()), + (NaiveTime::from_hms_opt(13, 30, 0).unwrap()), + (NaiveTime::from_hms_opt(14, 25, 0).unwrap()), + (NaiveTime::from_hms_opt(15, 15, 0).unwrap()), + ]; + + let mut table: Box<[[Option; 8]; 5]> = Box::new([0u8; 5].map(|_| [0u8; 8].map(|_| Option::::None))); + + for lesson in lessons { + let day_idx = lesson.date.weekday().num_days_from_monday() as usize; + + let mut l = Cow::::Owned(lesson); + for (period_idx, time) in lookup.iter().enumerate(){ + if l.start_time.0 < *time && &l.end_time.0 >= time{ + table[day_idx][period_idx] = Some(l.into_owned()); + l = Cow::Borrowed(&table[day_idx][period_idx].as_ref().unwrap()); + } + } + } + table +} + + +fn fetch_timetable(client: EspHttpConnection) -> Box { + let mut creds = include_str!("../untis-creds.txt").split('\n'); + + let server = creds.next().unwrap(); + let school_id = creds.next().unwrap(); + let usr = creds.next().unwrap(); + let password = creds.next().unwrap(); + + let mut s = untis::Client::login( + server, + school_id, + usr, + password, + client + ).unwrap(); + let cest = chrono::FixedOffset::east_opt(2 * 3600).unwrap(); + let now = s.date().unwrap().with_timezone(&cest); + println!("Current time: {}", now); + let date = now.date_naive().checked_add_days(Days::new(2)).unwrap(); + let lessons = s.own_timetable_for_week(&Date(date)).unwrap(); + + transform_lessons(lessons) +} \ No newline at end of file