Skip to content

Commit 7b60401

Browse files
Implement fetching gcode metadata
1 parent a99aec1 commit 7b60401

14 files changed

Lines changed: 188 additions & 54 deletions

moonraker-rs/src/moonraker_connection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ impl MoonrakerConnection {
258258
else {
259259
continue;
260260
}
261-
}, // TODO: This should eventually end
261+
},
262262
}
263263
}
264264
}

moonraker-rs/src/requests/file_management.rs

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::path::PathBuf;
2+
3+
use optional_struct::optional_struct;
14
use serde::Deserialize;
25

36
use crate::{error::Error, moonraker_connection::MoonrakerConnection};
@@ -10,21 +13,59 @@ pub struct MoonrakerFile {
1013
pub permissions: String,
1114
}
1215

13-
#[derive(Debug, Deserialize)]
16+
#[derive(Debug, Deserialize, PartialEq, Clone)]
1417
pub struct MoonrakerFileThumbnail {
1518
pub width: i32,
1619
pub height: i32,
1720
pub size: i32,
21+
#[serde(alias = "relative_path")]
1822
pub thumbnail_path: String,
1923
}
2024

25+
#[optional_struct]
26+
#[derive(Debug, Deserialize, Default)]
27+
pub struct GcodeMetadata {
28+
pub size: i32,
29+
pub modified: f32,
30+
pub uuid: String,
31+
pub file_processors: Vec<String>,
32+
pub slicer: String,
33+
pub slicer_version: String,
34+
pub gcode_start_byte: i32,
35+
pub gcode_int_byte: i32,
36+
pub object_height: f32,
37+
pub estimated_time: f32,
38+
pub nozzle_diameter: f32,
39+
pub layer_height: f32,
40+
pub first_layer_height: f32,
41+
pub first_layer_extr_temp: f32,
42+
pub first_layer_bed_temp: f32,
43+
pub chamber_temp: f32,
44+
pub filament_name: String,
45+
pub filament_colors: Vec<String>,
46+
pub extruder_colors: Vec<String>,
47+
pub filament_temps: Vec<i32>,
48+
pub filament_type: String,
49+
pub filament_total: f32,
50+
pub filament_change_count: i32,
51+
pub filament_weight_total: f32,
52+
pub filament_weights: Vec<f32>,
53+
pub mmu_print: i32,
54+
pub referenced_tools: Vec<i32>,
55+
pub thumbnails: Vec<MoonrakerFileThumbnail>,
56+
pub job_id: Option<String>,
57+
pub print_start_time: Option<f32>,
58+
pub filename: String,
59+
}
60+
2161
pub trait FileManagementRequestHandler {
2262
async fn list_files(&self, root: &str) -> Result<Vec<MoonrakerFile>, Error>;
2363
async fn list_gcode_files(&self) -> Result<Vec<MoonrakerFile>, Error>;
2464
async fn get_thumbnails_for_file(
2565
&self,
2666
file: &str,
2767
) -> Result<Vec<MoonrakerFileThumbnail>, Error>;
68+
async fn get_gcode_metadata_for_file(&self, filename: &str) -> Result<GcodeMetadata, Error>;
2869
}
2970

3071
impl FileManagementRequestHandler for MoonrakerConnection {
@@ -47,4 +88,75 @@ impl FileManagementRequestHandler for MoonrakerConnection {
4788
self.send_request("server.files.thumbnails", Some(args))
4889
.await
4990
}
91+
92+
async fn get_gcode_metadata_for_file(&self, filename: &str) -> Result<GcodeMetadata, Error>
93+
{
94+
let args = serde_json::json!({"filename": filename});
95+
let gcode_metadata : OptionalGcodeMetadata = self.send_request("server.files.metadata", Some(args)).await?;
96+
97+
Ok(GcodeMetadata::from_optional(gcode_metadata))
98+
}
5099
}
100+
101+
impl GcodeMetadata {
102+
pub fn from_optional(optional: OptionalGcodeMetadata) -> Self {
103+
Self {
104+
size: optional.size.unwrap_or_default(),
105+
modified: optional.modified.unwrap_or_default(),
106+
uuid: optional.uuid.unwrap_or_default(),
107+
file_processors: optional.file_processors.unwrap_or_default(),
108+
slicer: optional.slicer.unwrap_or_default(),
109+
slicer_version: optional.slicer_version.unwrap_or_default(),
110+
gcode_start_byte: optional.gcode_start_byte.unwrap_or_default(),
111+
gcode_int_byte: optional.gcode_int_byte.unwrap_or_default(),
112+
object_height: optional.object_height.unwrap_or_default(),
113+
estimated_time: optional.estimated_time.unwrap_or_default(),
114+
nozzle_diameter: optional.nozzle_diameter.unwrap_or_default(),
115+
layer_height: optional.layer_height.unwrap_or_default(),
116+
first_layer_height: optional.first_layer_height.unwrap_or_default(),
117+
first_layer_extr_temp: optional.first_layer_extr_temp.unwrap_or_default(),
118+
first_layer_bed_temp: optional.first_layer_bed_temp.unwrap_or_default(),
119+
chamber_temp: optional.chamber_temp.unwrap_or_default(),
120+
filament_name: optional.filament_name.unwrap_or_default(),
121+
filament_colors: optional.filament_colors.unwrap_or_default(),
122+
extruder_colors: optional.extruder_colors.unwrap_or_default(),
123+
filament_temps: optional.filament_temps.unwrap_or_default(),
124+
filament_type: optional.filament_type.unwrap_or_default(),
125+
filament_total: optional.filament_total.unwrap_or_default(),
126+
filament_change_count: optional.filament_change_count.unwrap_or_default(),
127+
filament_weight_total: optional.filament_weight_total.unwrap_or_default(),
128+
filament_weights: optional.filament_weights.unwrap_or_default(),
129+
mmu_print: optional.mmu_print.unwrap_or_default(),
130+
referenced_tools: optional.referenced_tools.unwrap_or_default(),
131+
thumbnails: optional.thumbnails.unwrap_or_default(),
132+
job_id: optional.job_id.clone(),
133+
print_start_time: optional.print_start_time.clone(),
134+
filename: optional.filename.unwrap_or_default(),
135+
}
136+
}
137+
138+
pub fn absolute_thumbnails(&self) -> Vec<MoonrakerFileThumbnail>
139+
{
140+
let buf = PathBuf::from(&self.filename);
141+
let base_path = buf
142+
.parent()
143+
.and_then(|f| Some(f.to_str().unwrap()))
144+
.unwrap_or("");
145+
146+
self.thumbnails
147+
.iter()
148+
.map(|f| {
149+
MoonrakerFileThumbnail {
150+
width: f.width,
151+
height: f.height,
152+
size: f.size,
153+
thumbnail_path: if base_path.is_empty() {
154+
f.thumbnail_path.clone()
155+
} else {
156+
format!("{}/{}", base_path, f.thumbnail_path)
157+
}
158+
}
159+
})
160+
.collect()
161+
}
162+
}

src/main.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,21 +81,22 @@ async fn main() -> Result<(), Box<dyn Error>> {
8181
});
8282

8383
register_filesystem_list_files(&ui, &moonraker_connection);
84-
register_filesystem_download_thumbnails(&ui, &moonraker_connection);
84+
register_filesystem_fetch_metadata(&ui, &moonraker_connection);
8585

8686
register_temperature_set_new_target_temperature(&ui, &moonraker_connection);
8787

8888
register_util_image_exists(&ui);
8989
register_util_format_bytes(&ui);
9090
register_util_prettify_name(&ui);
91-
register_create_temperature_lists(&ui);
92-
register_convert_temperature_back(&ui);
91+
register_util_time_in_seconds_to_string(&ui);
92+
register_util_create_temperature_lists(&ui);
93+
register_util_convert_temperature_back(&ui);
9394

9495
register_printer_emergency_stop(&ui, &moonraker_connection);
9596
register_printer_firmware_restart(&ui, &moonraker_connection);
9697
register_printer_restart(&ui, &moonraker_connection);
9798

98-
let gcode_command_config = &config.gcode_commands.unwrap_or(OptionalGcodeCommands::default());
99+
let gcode_command_config = &config.gcode_commands.unwrap_or_default();
99100
register_extruder_extrude(&ui, &moonraker_connection, gcode_command_config);
100101
register_extruder_retract(&ui, &moonraker_connection, gcode_command_config);
101102
register_extruder_load_filament(&ui, &moonraker_connection, gcode_command_config);

src/ui_functions/filesystem_download_thumbnail.rs renamed to src/ui_functions/filesystem_fetch_metadata.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
use std::sync::Arc;
22

33
use moonraker_rs::{moonraker_connection::{MoonrakerConnection}, requests::FileManagementRequestHandler};
4-
use slint::{ComponentHandle, Image, Model, Rgba8Pixel, SharedPixelBuffer, VecModel};
4+
use slint::{ComponentHandle, Image, Model, Rgba8Pixel, SharedPixelBuffer, SharedString, VecModel};
55
use tokio::sync::Mutex;
66

77
use crate::{AppWindow, Filesystem, MoonrakerFile};
88

9-
pub fn register_filesystem_download_thumbnails(ui: &AppWindow, moonraker_connection : &Arc<MoonrakerConnection>)
9+
pub fn register_filesystem_fetch_metadata(ui: &AppWindow, moonraker_connection : &Arc<MoonrakerConnection>)
1010
{
1111
let mutex = Arc::new(Mutex::new(()));
1212
let ui_weak = ui.as_weak();
1313
let moonraker_connection = moonraker_connection.clone();
1414

1515
ui.global::<Filesystem>()
16-
.on_download_thumbnail(move |global_index| {
16+
.on_fetch_metadata(move |global_index| {
1717
let mutex = mutex.clone();
1818
let ui_weak = ui_weak.clone();
1919
let moonraker_connection = moonraker_connection.clone();
@@ -42,13 +42,21 @@ pub fn register_filesystem_download_thumbnails(ui: &AppWindow, moonraker_connect
4242
}
4343

4444
// TODO: Error handling
45-
let files = moonraker_connection
46-
.get_thumbnails_for_file(&file.path)
45+
let metadata = moonraker_connection
46+
.get_gcode_metadata_for_file(&file.path)
4747
.await
4848
.unwrap();
49+
50+
file.filament_used_gram = metadata.filament_weight_total;
51+
file.filament_type = SharedString::from(&metadata.filament_type);
52+
file.height_mm = metadata.object_height;
53+
file.estimated_time_s = metadata.estimated_time;
54+
file.layer_height_mm = metadata.layer_height;
55+
file.nozzle_diameter_mm = metadata.nozzle_diameter;
56+
57+
let files = metadata.absolute_thumbnails();
4958
println!("Thumbnails for {}: {:?}", file.path, files);
50-
let possible_target =
51-
files.into_iter().find(|f| f.width == 32 && f.height == 32);
59+
let possible_target = files.into_iter().find(|f| f.width == 32 && f.height == 32);
5260

5361
if let Some(target) = possible_target {
5462
let data = moonraker_connection
@@ -67,8 +75,9 @@ pub fn register_filesystem_download_thumbnails(ui: &AppWindow, moonraker_connect
6775

6876
file.thumbnail = Image::from_rgba8(shared_buf);
6977
println!("Set thumbnail for file {}", file.path);
70-
non_optional_files.set_vec(unwrapped_files);
7178
}
79+
80+
non_optional_files.set_vec(unwrapped_files);
7281
}
7382
})
7483
.unwrap();

src/ui_functions/filesystem_list_files.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,16 @@ pub fn register_filesystem_list_files(ui : &AppWindow, moonraker_connection : &A
4848
modified: f.modified,
4949
size: f.size,
5050
permissions: SharedString::from(&f.permissions),
51-
thumbnail: Image::default(),
51+
..MoonrakerFile::default()
5252
})
5353
.collect();
5454

5555
ui.global::<Filesystem>()
5656
.set_files(ModelRc::new(Rc::new(VecModel::from(converted_files))));
5757
ui.global::<Filesystem>().set_loading(false);
58-
ui.global::<Filesystem>().invoke_download_thumbnail(0);
59-
ui.global::<Filesystem>().invoke_download_thumbnail(1);
60-
ui.global::<Filesystem>().invoke_download_thumbnail(2);
61-
ui.global::<Filesystem>().invoke_download_thumbnail(3);
62-
ui.global::<Filesystem>().invoke_download_thumbnail(4);
58+
for i in 0..5 {
59+
ui.global::<Filesystem>().invoke_fetch_metadata(i);
60+
}
6361
})
6462
.unwrap();
6563
});

src/ui_functions/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub mod util_format_bytes;
2-
pub mod filesystem_download_thumbnail;
2+
pub mod filesystem_fetch_metadata;
33
pub mod util_image_exists;
44
pub mod filesystem_list_files;
55
pub mod util_prettify_name;
@@ -11,9 +11,10 @@ pub mod printer_execute_gcode_command;
1111
pub mod util_create_temperature_list;
1212
pub mod settings_set_ui_settings;
1313
pub mod quick_action_execute;
14+
pub mod util_time_in_seconds_to_string;
1415

1516
pub use util_format_bytes::*;
16-
pub use filesystem_download_thumbnail::*;
17+
pub use filesystem_fetch_metadata::*;
1718
pub use util_image_exists::*;
1819
pub use filesystem_list_files::*;
1920
pub use util_prettify_name::*;
@@ -24,4 +25,5 @@ pub use printer_firmware_restart::*;
2425
pub use printer_execute_gcode_command::*;
2526
pub use util_create_temperature_list::*;
2627
pub use settings_set_ui_settings::*;
27-
pub use quick_action_execute::*;
28+
pub use quick_action_execute::*;
29+
pub use util_time_in_seconds_to_string::*;

src/ui_functions/util_create_temperature_list.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel};
22

33
use crate::{AppWindow, Utils};
44

5-
pub fn register_create_temperature_lists(ui : &AppWindow)
5+
pub fn register_util_create_temperature_lists(ui : &AppWindow)
66
{
77
ui.global::<Utils>().on_create_temperature_lists(|presets| {
88
let presets = presets.as_any().downcast_ref::<VecModel<i32>>().unwrap();
@@ -20,7 +20,7 @@ pub fn register_create_temperature_lists(ui : &AppWindow)
2020
});
2121
}
2222

23-
pub fn register_convert_temperature_back(ui : &AppWindow)
23+
pub fn register_util_convert_temperature_back(ui : &AppWindow)
2424
{
2525
ui.global::<Utils>().on_convert_temperature_back(|f| {
2626
let s = f.trim_end_matches("°C");
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use slint::{ComponentHandle, SharedString};
2+
3+
use crate::{AppWindow, Utils};
4+
5+
pub fn register_util_time_in_seconds_to_string(ui : &AppWindow)
6+
{
7+
ui.global::<Utils>().on_time_in_seconds_to_string(|f: f32| {
8+
let total_seconds = f.round() as i32;
9+
let hours = total_seconds / 3600;
10+
let minutes = (total_seconds % 3600) / 60;
11+
let seconds = total_seconds % 60;
12+
13+
if hours > 0 {
14+
SharedString::from(format!("{}h{:02}m", hours, minutes))
15+
} else if total_seconds >= 60 {
16+
SharedString::from(format!("{}m", minutes))
17+
} else {
18+
SharedString::from(format!("{}s", seconds))
19+
}
20+
});
21+
}

ui/components/page.slint

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,13 @@
11
import { StyleMetrics } from "std-widgets.slint";
22

33
export component Page inherits Rectangle {
4-
in property <string> header <=> h.text;
5-
width: 100%;
6-
height: 100%;
4+
in property <string> header;
75

8-
VerticalLayout {
9-
width: 100%;
10-
height: 100%;
11-
HorizontalLayout {
12-
x: 10px;
13-
h := Text {
14-
font-weight: 900;
15-
horizontal-alignment: left;
16-
y: 2px;
17-
}
18-
padding-bottom: 4px;
19-
vertical-stretch: 0;
20-
}
21-
22-
GridLayout {
23-
padding: StyleMetrics.layout-padding / 2;
24-
Rectangle {
25-
vertical-stretch: 1;
26-
@children
27-
}
6+
GridLayout {
7+
padding: StyleMetrics.layout-padding / 2;
8+
Rectangle {
9+
vertical-stretch: 1;
10+
@children
2811
}
2912
}
3013
}

ui/pages/file-list-page.slint

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export component FileListPage inherits Page
2020
width: 200px;
2121
}
2222

23-
if !Filesystem.loading && selected_file.path == "": ScrollView {
23+
if !Filesystem.loading && selected_file.path == "": Flickable {
2424
VerticalLayout {
2525
for f in Filesystem.files: Rectangle {
2626
height: 40px;
@@ -39,7 +39,7 @@ export component FileListPage inherits Page
3939
width: 32px;
4040
}
4141
Text { text: f.path; horizontal-stretch: 1; vertical-alignment: center; overflow: elide; }
42-
Text { text: Utils.format_bytes(f.size); horizontal-alignment: right; vertical-alignment: center; }
42+
Text { text: f.filament-type != "" ? f.filament_type + " - " + Utils.time_in_seconds_to_string(f.estimated-time-s) : Utils.time_in_seconds_to_string(f.estimated-time-s); horizontal-alignment: right; vertical-alignment: center; }
4343
}
4444
}
4545
}
@@ -54,7 +54,7 @@ export component FileListPage inherits Page
5454
Text { text: "Size: " + Utils.format_bytes(selected_file.size); }
5555
Text { text: "Modified: " + selected_file.modified; }
5656
Text { text: "Permissions: " + selected_file.permissions; }
57-
Button { text: "Close"; clicked => { root.selected_file = {}; Filesystem.download_thumbnail(thumbnail_index); thumbnail_index += 1; } }
57+
Button { text: "Close"; clicked => { root.selected_file = {}; thumbnail_index += 1; } }
5858
}
5959
}
6060
}

0 commit comments

Comments
 (0)