diff --git a/client/bin/Cargo.toml b/client/bin/Cargo.toml index 4f141b1..51bbb76 100644 --- a/client/bin/Cargo.toml +++ b/client/bin/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "LEDboardClient" +name = "ledboard_client" version = "0.1.0" edition = "2021" @@ -10,7 +10,7 @@ embedded-graphics = "0.8.0" substring = "1.4.5" tinybmp = "0.5.0" openweathermap = { path = "../openweathermap" } -chrono = { version = "0.4.23", default-features = false , features = ["iana-time-zone"] } +chrono = { version = "0.4.23", default-features = false , features = ["clock", "std","iana-time-zone"] } chrono-tz = "0.8.0" colored = "2.0.0" datetime = "0.5.2" diff --git a/client/bin/src/main.rs b/client/bin/src/main.rs index 1fa2072..dbc84dd 100644 --- a/client/bin/src/main.rs +++ b/client/bin/src/main.rs @@ -1,7 +1,8 @@ -use std::time::Duration; +use std::{time::Duration, fmt::format}; use bit::BitIndex; use chrono_tz::Europe::Berlin; use chrono::{DateTime, NaiveDateTime, Utc, Timelike}; +use chrono::prelude::*; use std::time::{SystemTime, UNIX_EPOCH}; use openweathermap::forecast::Weather; use substring::Substring; @@ -12,7 +13,6 @@ use embedded_graphics::{ mono_font::{iso_8859_1::FONT_6X10, iso_8859_1::FONT_5X8, MonoTextStyle}, pixelcolor::BinaryColor, prelude::*, - primitives::PrimitiveStyle, text::Text, }; @@ -22,7 +22,6 @@ use std::io; use openweathermap::forecast::Forecast; use straba::NextDeparture; -use ping; // This declaration will look for a file named `straba.rs` and will // insert its contents inside a module named `straba` under this scope mod straba; @@ -36,10 +35,6 @@ const IMAGE_HEIGHT_BYTE: u32 = 40; const IMAGE_LENGTH: usize = (IMAGE_WIDTH_BYTE * IMAGE_HEIGHT_BYTE) as usize; const PACKAGE_LENGTH: usize = (IMAGE_LENGTH + 1) as usize; -const PRIMITIVE_STYLE:PrimitiveStyle = PrimitiveStyle::with_stroke(BinaryColor::On, 1); - - - struct UdpDisplay { image: [u8; IMAGE_SIZE_BYTE], @@ -131,6 +126,7 @@ fn render_weather(display: &mut UdpDisplay ,data: &Option { + let mut temp:&f64 = &-1_f64; if !result.list.is_empty() { let mut max:f64 = 0_f64; let mut best = &result.list[0]; @@ -143,11 +139,14 @@ fn render_weather(display: &mut UdpDisplay ,data: &Option::default(); + let cur_time = chrono::offset::Utc::now(); if zoned_time > cur_time { println!("Skipping old result {hour}:{minute} @{time_s}"); } + temp = &forecast.main.temp; + println!("Forecast Temp is {temp}°C"); + match &forecast.rain { Some(x) => { let rain_v = x.three_hours; @@ -159,7 +158,6 @@ fn render_weather(display: &mut UdpDisplay ,data: &Option println!("No rain at {hour}:{minute}"), } - } @@ -168,7 +166,14 @@ fn render_weather(display: &mut UdpDisplay ,data: &Option2}:{minute:0>2}:{second:0>2}"); + let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); + Text::new(&time, Point::new((1) as i32, 7), text_style) + .draw(display) + .unwrap(); +} + fn send_package(ipaddress: String, data: &Option>, - strabaRes: &NextDeparture) { + straba_res: &NextDeparture) { let mut package: [u8; PACKAGE_LENGTH] = [0; PACKAGE_LENGTH]; // Brightness @@ -236,31 +254,31 @@ fn send_package(ipaddress: String, image: [0; IMAGE_SIZE_BYTE], }; - if (data.is_some()) { + if data.is_some() { render_weather(&mut display, data); } - if strabaRes.failure == false { + if straba_res.failure == false { let text_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); let text_style_station = MonoTextStyle::new(&FONT_5X8, BinaryColor::On); - let mut outbound = format!("+{}min", (strabaRes.outbound_diff / 60)); - if (strabaRes.outbound_diff < 60) { + let mut outbound = format!("{}min", (straba_res.outbound_diff / 60)); + if straba_res.outbound_diff < 60 { outbound = String::from("sofort"); } - Text::new(&strabaRes.outbound_station, Point::new(1, 15), text_style_station) + Text::new(&straba_res.outbound_station, Point::new(1, 15), text_style_station) .draw(&mut display) .unwrap(); Text::new(&outbound, Point::new(80, 15), text_style) .draw(&mut display) .unwrap(); - let mut inbound = format!("+{}min", (strabaRes.inbound_diff / 60)); - if (strabaRes.inbound_diff < 60) { + let mut inbound = format!("{}min", (straba_res.inbound_diff / 60)); + if straba_res.inbound_diff < 60 { inbound = String::from("sofort"); } - Text::new(&strabaRes.inbound_station, Point::new(1, 25), text_style_station) + Text::new(&straba_res.inbound_station, Point::new(1, 25), text_style_station) .draw(&mut display) .unwrap(); Text::new(&inbound, Point::new(80, 24), text_style) @@ -268,6 +286,11 @@ fn send_package(ipaddress: String, .unwrap(); } + + + render_clock(&mut display); + + package[1..PACKAGE_LENGTH].copy_from_slice(&display.image); // client need to bind to client port (1 before 4242) let socket = UdpSocket::bind("0.0.0.0:14242").expect("couldn't bind to address"); @@ -286,12 +309,12 @@ LEDboardClient " } fn check_connection(ipaddress: String) -> bool { - let mut device_online = false; + let device_online; // generate a faulty package length let mut package: [u8; PACKAGE_LENGTH/2] = [0; PACKAGE_LENGTH/2]; // client need to bind to client port (1 before 4242) let socket = UdpSocket::bind("0.0.0.0:14242").expect("couldn't bind to address"); - socket.set_read_timeout(Some(Duration::from_secs(10))); /* 10 seconds timeout */ + socket.set_read_timeout(Some(Duration::from_secs(10))).unwrap(); /* 10 seconds timeout */ socket .send_to(&package, ipaddress + ":4242") .expect("couldn't send data"); @@ -299,14 +322,14 @@ fn check_connection(ipaddress: String) -> bool { // self.recv_buff is a [u8; 8092] let answer = socket.recv_from(&mut package); match answer { - Ok((n, addr)) => { + Ok((_n, _addr)) => { //println!("{} bytes response from {:?} {:?}", n, addr, &package[..n]); device_online = true; } Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { device_online = false; } - Err(e) => { + Err(_e) => { device_online = false; } } @@ -328,7 +351,7 @@ fn main() { let mut device_online = check_connection(ip.to_string()); - if (!device_online) { + if !device_online { println!("{} not online", ip); return } @@ -342,16 +365,16 @@ fn main() { let mut last_data = Option::None; // Test Webcrawler for public transportataion - let mut strabaRes = straba::fetch_data(Some(true)); - println!("{:?} {:?}s", strabaRes.outbound_station, strabaRes.outbound_diff); - println!("{:?} {:?}s", strabaRes.inbound_station , strabaRes.inbound_diff); + let mut straba_res = straba::fetch_data(Some(true)); + println!("{:?} {:?}s", straba_res.outbound_station, straba_res.outbound_diff); + println!("{:?} {:?}s", straba_res.inbound_station , straba_res.inbound_diff); // Render start - send_package(ip.to_string(), &last_data, &strabaRes); + send_package(ip.to_string(), &last_data, &straba_res); loop { let st_now = SystemTime::now(); let seconds = st_now.duration_since(UNIX_EPOCH).unwrap().as_secs(); - let delay = time::Duration::from_millis(10000); + let delay = time::Duration::from_millis(500); thread::sleep(delay); // Only request, if the device is present if device_online == true { @@ -366,19 +389,19 @@ fn main() { } } - if (strabaRes.request_time + 60) < seconds as i64 { + if (straba_res.request_time + 60) < seconds as i64 { device_online = check_connection(ip.to_string()); // request once a minute new data if device_online == true { - strabaRes = straba::fetch_data(None); - println!("Update {:?} {:?}s", strabaRes.outbound_station, strabaRes.outbound_diff); - println!("Update {:?} {:?}s", strabaRes.inbound_station , strabaRes.inbound_diff); + straba_res = straba::fetch_data(None); + println!("Update {:?} {:?}s", straba_res.outbound_station, straba_res.outbound_diff); + println!("Update {:?} {:?}s", straba_res.inbound_station , straba_res.inbound_diff); } } if device_online == true { // Render new image - send_package(ip.to_string(), &last_data, &strabaRes); + send_package(ip.to_string(), &last_data, &straba_res); } } } diff --git a/client/bin/src/straba.rs b/client/bin/src/straba.rs index 9398baf..86f80ff 100644 --- a/client/bin/src/straba.rs +++ b/client/bin/src/straba.rs @@ -1,11 +1,6 @@ use chrono::DateTime; use std::time::{SystemTime, UNIX_EPOCH}; -use chrono_tz::Europe::Berlin; -/* @file straba.rs - * @brief fetch next depature of light rail vehicle - */ -use serde_json::Value; use serde::Deserialize; const STATION_URL:&str = "https://www.rnv-online.de/rest/departure/2494"; @@ -16,7 +11,8 @@ const STATION_URL:&str = "https://www.rnv-online.de/rest/departure/2494"; pub struct Station { pub id: String, pub name: String, - pub graphQL: GraphQL, + #[serde(alias = "graphQL")] + pub graph_ql: GraphQL, } #[derive(Default, Debug, Clone, PartialEq, Deserialize)] @@ -41,7 +37,7 @@ pub struct JourneysElement { #[derive(Default, Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Line { - pub lineGroup: LineGroup, + pub line_group: LineGroup, } #[derive(Default, Debug, Clone, PartialEq, Deserialize)] @@ -61,15 +57,15 @@ pub struct Journey { #[derive(Default, Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct StopsElement { - pub destinationLabel: String, - pub plannedDeparture: IsoStringDateTime, - pub realtimeDeparture: IsoStringDateTime, + pub destination_label: String, + pub planned_departure: IsoStringDateTime, + pub realtime_departure: IsoStringDateTime, } #[derive(Default, Debug, Clone, PartialEq, Deserialize)] #[serde(rename_all = "camelCase")] pub struct IsoStringDateTime { - pub isoString: Option, + pub iso_string: Option, } // Return value @@ -89,7 +85,7 @@ pub fn fetch_data(debug_print : Option) -> NextDeparture { let url = &format!("{}?datetime={}", STATION_URL, seconds); let result = reqwest::blocking::get(url); - let mut returnValue = NextDeparture { + let mut return_value = NextDeparture { failure : false, outbound_station : String::from(""), outbound_diff : 10000, @@ -100,64 +96,64 @@ pub fn fetch_data(debug_print : Option) -> NextDeparture { if result.is_err() { println!("Could not read station response {:?}", result.err()); - returnValue.failure = true; - return returnValue; + return_value.failure = true; + return return_value; } let text = result.unwrap().text(); if text.is_err() { println!("Could not convert response {:?}", text.err()); - returnValue.failure = true; - return returnValue; + return_value.failure = true; + return return_value; } - let rawText = &text.unwrap(); - let body: std::result::Result = serde_json::from_str(&rawText); + let raw_text = &text.unwrap(); + let body: std::result::Result = serde_json::from_str(&raw_text); if body.is_err() { println!("Could not parse json {:?}", body.err()); println!("------------------------- %< ----------------------------"); - println!("{}", &rawText); + println!("{}", &raw_text); println!("------------------------- %< ----------------------------"); - returnValue.failure = true; - return returnValue; + return_value.failure = true; + return return_value; } // parse JSON result.. search of both directions let json = body.unwrap(); - for el in (json.graphQL.response.journeys.elements) { - if (debug_print.is_some() && debug_print.unwrap() == true) { - println!("Line {:}", el.line.lineGroup.label); + for el in json.graph_ql.response.journeys.elements { + if debug_print.is_some() && debug_print.unwrap() == true { + println!("Line {:}", el.line.line_group.label); } for stop in el.stops { // use only valid data - if stop.realtimeDeparture.isoString.is_some() && - stop.destinationLabel != "" { - let txt_departure = stop.realtimeDeparture.isoString.unwrap(); + if stop.realtime_departure.iso_string.is_some() && + stop.destination_label != "" { + let txt_departure = stop.realtime_departure.iso_string.unwrap(); let next_departure = DateTime::parse_from_rfc3339(&txt_departure).unwrap(); let diff = next_departure.timestamp() - (seconds as i64); - if (debug_print.is_some() && debug_print.unwrap() == true) { - println!("To {:} {:} (in {:} seconds)", stop.destinationLabel, txt_departure, diff ); + if debug_print.is_some() && debug_print.unwrap() == true { + println!("To {:} {:} (in {:} seconds)", stop.destination_label, txt_departure, diff ); } - if stop.destinationLabel.contains("Rheinau") { - if (diff < returnValue.outbound_diff) { - returnValue.outbound_station = stop.destinationLabel; - returnValue.outbound_diff = diff; + if stop.destination_label.contains("Rheinau") { + if diff < return_value.outbound_diff { + return_value.outbound_station = stop.destination_label; + return_value.outbound_diff = diff; } - } else if stop.destinationLabel.contains("Hochschule") || - stop.destinationLabel.contains("Hauptbahnhof") || - stop.destinationLabel.contains("Schönau") { - if (diff < returnValue.inbound_diff) { - returnValue.inbound_station = stop.destinationLabel; - returnValue.inbound_diff = diff; + } else if stop.destination_label.contains("Hochschule") || + stop.destination_label.contains("Hauptbahnhof") || + stop.destination_label.contains("Schönau") { + if diff < return_value.inbound_diff { + return_value.inbound_station = stop.destination_label; + return_value.inbound_diff = diff; } } } else { - println!("Planned {:} {:?}", stop.destinationLabel, stop.plannedDeparture.isoString) + println!("Planned {:} {:?}", stop.destination_label, stop.planned_departure.iso_string) } } } - returnValue + return_value } diff --git a/client/openweathermap/src/lib.rs b/client/openweathermap/src/lib.rs old mode 100755 new mode 100644