Fix weather plot, close #5
This commit is contained in:
parent
e8f5f00386
commit
d537c6f7be
2 changed files with 130 additions and 22 deletions
|
@ -28,7 +28,7 @@ pub struct WeatherData {
|
|||
#[serde(skip_deserializing)]
|
||||
minutely: Vec<()>,
|
||||
/// Weather Information for the coming hours
|
||||
hourly: Vec<HourlyWeather>,
|
||||
pub hourly: Vec<HourlyWeather>,
|
||||
/// Weather information for the next days _(unused at the moment)_
|
||||
#[serde(skip_deserializing)]
|
||||
daily: Vec<()>,
|
||||
|
@ -95,6 +95,12 @@ pub struct HourlyWeather {
|
|||
pub(self) pop: f32,
|
||||
}
|
||||
|
||||
impl HourlyWeather {
|
||||
pub fn temperature(&self) -> f32 {
|
||||
self.data.temp
|
||||
}
|
||||
}
|
||||
|
||||
/// Common weather information shared among different forecast types.
|
||||
///
|
||||
/// This struct is not instantiated by the API but merely introduced by the `Deserializer`.
|
||||
|
|
|
@ -1,22 +1,129 @@
|
|||
use crate::error::display_no_data;
|
||||
use embedded_graphics::mono_font::MonoTextStyleBuilder;
|
||||
use embedded_graphics::{
|
||||
draw_target::DrawTarget,
|
||||
image::Image,
|
||||
mono_font::MonoTextStyle,
|
||||
prelude::*,
|
||||
text::Text
|
||||
draw_target::DrawTarget, image::Image, mono_font::MonoTextStyle, prelude::*, text::Text,
|
||||
};
|
||||
use embedded_plots::{axis::Scale, curve::Curve, single_plot::SinglePlot};
|
||||
use profont::{
|
||||
PROFONT_14_POINT, PROFONT_24_POINT, PROFONT_7_POINT, PROFONT_9_POINT,
|
||||
use embedded_plots::{
|
||||
axis::{Axis, Placement, Scale},
|
||||
curve::{Curve, PlotPoint},
|
||||
single_plot::SinglePlot,
|
||||
};
|
||||
use profont::{PROFONT_14_POINT, PROFONT_24_POINT, PROFONT_7_POINT, PROFONT_9_POINT};
|
||||
use ssd1675::Color;
|
||||
use std::fmt::Debug;
|
||||
use crate::error::display_no_data;
|
||||
use std::ops::Range;
|
||||
use time::OffsetDateTime;
|
||||
|
||||
mod api;
|
||||
mod data;
|
||||
mod secret;
|
||||
mod icons;
|
||||
mod secret;
|
||||
|
||||
/// Draws the 24hr weather data in a graph with 2 x axes, one for today and one for tomorrow.
|
||||
fn draw_weather_plot<D>(
|
||||
wtr: &data::WeatherData,
|
||||
display: &mut D,
|
||||
top_left: Point,
|
||||
bottom_right: Point,
|
||||
) where
|
||||
D: DrawTarget<Color = Color>,
|
||||
D::Error: Debug,
|
||||
{
|
||||
let local_time =
|
||||
OffsetDateTime::now_local().expect("Failed to retrieve current time from system clock");
|
||||
let now_hour = local_time.hour();
|
||||
|
||||
// Split the plot data into two sets: one for today's data (time up to 23:00), one for tomorrow
|
||||
// (0:00 onwards). This is necessary because if all data were plotted in one graph, it would
|
||||
// show the delta in hours to the current time. If you replaced the delta with the actual hour,
|
||||
// the plot would be re-ordered, leading to confusion.
|
||||
// NOTE(feliix42): We're doing a +1 here to actually also take the 24 for a better overlap
|
||||
let num_entries_today = 24 - now_hour + 1;
|
||||
let num_entries_tomorrow = 24 - num_entries_today;
|
||||
|
||||
let plot_data = wtr.forecast_plot_data();
|
||||
|
||||
// X coordinate where to split between axis 1 and 2
|
||||
let cutoff_point = top_left.x + ((bottom_right.x - top_left.x) / 24) * num_entries_today as i32;
|
||||
|
||||
// computation of scales. We want 5 (plus x origin) labels on the x axis. So we compute as
|
||||
// follows: num_labels % 6 = num labels per section
|
||||
// Note, that the origin of x2 will be printed anyways as well
|
||||
let num_labels_in_x1: u8 = num_entries_today / 6;
|
||||
let x1_labels = if num_labels_in_x1 > 0 {
|
||||
num_labels_in_x1
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let mut x2_labels = 5 - x1_labels;
|
||||
if x2_labels == 0 {
|
||||
x2_labels = 1;
|
||||
}
|
||||
|
||||
let x1_scale = Scale::RangeFraction(x1_labels.into());
|
||||
let x2_scale = Scale::RangeFraction(x2_labels.into());
|
||||
let y_scale = Scale::RangeFraction(2);
|
||||
let thickness = 2;
|
||||
let axis_thickness = thickness;
|
||||
let text_style = MonoTextStyleBuilder::new().text_color(Color::Black).build();
|
||||
|
||||
let curve = [(Curve::from_data(&plot_data), Color::Black)];
|
||||
|
||||
let x1_range: Range<i32> = (now_hour as i32)..((now_hour + num_entries_today) as i32);
|
||||
let x2_range: Range<i32> = 0..(num_entries_tomorrow as i32);
|
||||
let y_range = curve[0].0.y_range.clone();
|
||||
|
||||
Axis::new(x1_range)
|
||||
.set_title("")
|
||||
.set_scale(x1_scale)
|
||||
.into_drawable_axis(Placement::X {
|
||||
x1: top_left.x,
|
||||
x2: cutoff_point,
|
||||
y: bottom_right.y,
|
||||
})
|
||||
.set_color(Color::Black)
|
||||
.set_text_style(text_style)
|
||||
.set_tick_size(2)
|
||||
.set_thickness(axis_thickness)
|
||||
.draw(display)
|
||||
.expect("Failed to draw the temperature plot");
|
||||
Axis::new(x2_range)
|
||||
.set_title("t")
|
||||
.set_scale(x2_scale)
|
||||
.into_drawable_axis(Placement::X {
|
||||
x1: cutoff_point,
|
||||
x2: bottom_right.x,
|
||||
y: bottom_right.y,
|
||||
})
|
||||
.set_color(Color::Black)
|
||||
.set_text_style(text_style)
|
||||
.set_tick_size(2)
|
||||
.set_thickness(axis_thickness)
|
||||
.draw(display)
|
||||
.expect("Failed to draw the temperature plot");
|
||||
Axis::new(y_range)
|
||||
.set_title("C")
|
||||
.set_scale(y_scale)
|
||||
.into_drawable_axis(Placement::Y {
|
||||
y1: top_left.y,
|
||||
y2: bottom_right.y,
|
||||
x: top_left.x,
|
||||
})
|
||||
.set_color(Color::Black)
|
||||
.set_text_style(text_style)
|
||||
.set_tick_size(2)
|
||||
.set_thickness(axis_thickness)
|
||||
.draw(display)
|
||||
.expect("Failed to draw the temperature plot");
|
||||
|
||||
curve[0]
|
||||
.0
|
||||
.into_drawable_curve(&top_left, &bottom_right)
|
||||
.set_color(curve[0].1)
|
||||
.set_thickness(thickness)
|
||||
.draw(display)
|
||||
.expect("Failed to draw the temperature plot");
|
||||
}
|
||||
|
||||
pub fn get_weather<D>(display: &mut D)
|
||||
where
|
||||
|
@ -107,15 +214,10 @@ where
|
|||
.expect("error drawing text");
|
||||
|
||||
// Plot the forecast
|
||||
// TODO(feliix42): Annotate the plot better??
|
||||
let data_points = weather_data.forecast_plot_data();
|
||||
let curve = [(Curve::from_data(&data_points), Color::Black)];
|
||||
|
||||
let plot = SinglePlot::new(&curve, Scale::RangeFraction(4), Scale::RangeFraction(2))
|
||||
.into_drawable(Point::new(100, 54), Point::new(206, 94))
|
||||
.set_color(Color::Black);
|
||||
|
||||
plot.draw(display)
|
||||
.expect("Failed to draw the temperature plot");
|
||||
draw_weather_plot(
|
||||
&weather_data,
|
||||
display,
|
||||
Point::new(100, 54),
|
||||
Point::new(206, 94),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue