embedded_wg_display/util/
esptime.rs1use crate::runtime::http_sync;
6use crate::runtime::widget::widget::clocks::Datetime;
7use esp_hal::time::Instant;
8use serde::Deserialize;
9
10#[derive(Clone, Debug)]
11pub struct EspTime {
12 fetch_time_offset: Option<Instant>,
13 fetched_time_epoch: Option<u64>,
14}
15
16#[derive(Deserialize)]
18struct TimeApiResponse {
19 unix_timestamp: u64,
20}
21
22impl EspTime {
23 pub fn new() -> Self {
25 Self {
26 fetch_time_offset: None,
27 fetched_time_epoch: None,
28 }
29 }
30
31 pub async fn fetch_time(&mut self) {
37 let response = http_sync::http_request_async(http_sync::HttpRequest {
40 method: reqwless::request::Method::GET,
41 url: alloc::string::String::from("https://timeapi.io/api/v1/time/current/unix"),
42 body: None,
43 })
44 .await
45 .expect("Failed to fetch time API response");
46
47 self.fetch_time_offset = Some(Instant::now());
48
49 let body = alloc::string::String::from_utf8(response.bytes)
51 .expect("Failed to parse response as UTF-8");
52 let parsed: TimeApiResponse =
53 serde_json::from_str(body.trim()).expect("Failed to parse time API JSON");
54
55 self.fetched_time_epoch = Some(parsed.unix_timestamp);
56 }
57
58 pub fn now(&self) -> Option<Datetime> {
62 match (self.fetch_time_offset, self.fetched_time_epoch) {
63 (Some(offset), Some(epoch)) => {
64 let elapsed = Instant::now() - offset;
65 let seconds = epoch.saturating_add(elapsed.as_secs());
66 let nanoseconds = ((elapsed.as_micros() % 1_000_000) * 1_000) as u32;
67 Some(Datetime {
68 seconds,
69 nanoseconds,
70 })
71 }
72 _ => None,
73 }
74 }
75}