add status command to fetch printer status

This commit is contained in:
sigil-03 2026-01-04 14:20:31 -07:00
parent 430084a0f1
commit 944f480758

View file

@ -1,12 +1,11 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use core::time::Duration; use core::time::Duration;
use reqwest::blocking::Client;
use serde::{Deserialize, Serialize};
use std::fs; use std::fs;
use thiserror::Error; use thiserror::Error;
use serde::Deserialize;
use reqwest::blocking::Client;
use uuid::Uuid; use uuid::Uuid;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct Telemetry { struct Telemetry {
#[serde(rename = "temp-bed")] #[serde(rename = "temp-bed")]
@ -25,7 +24,27 @@ struct Info {
telemetry: Telemetry, telemetry: Telemetry,
// temperature: Temperature, // temperature: Temperature,
state: State, state: State,
}
#[derive(Serialize, Deserialize, Debug)]
struct JobStatus {
progress: f32,
time_printing: usize,
}
#[derive(Serialize, Deserialize, Debug)]
struct PrinterStatus {
state: String,
temp_bed: f32,
target_bed: f32,
temp_nozzle: f32,
target_nozzle: f32,
}
#[derive(Serialize, Deserialize, Debug)]
struct Status {
job: Option<JobStatus>,
printer: Option<PrinterStatus>,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
@ -42,7 +61,7 @@ struct Storage {
struct Prusa { struct Prusa {
api_key: String, api_key: String,
ip_addr: String, ip_addr: String,
client: Client, client: Client,
} }
impl Prusa { impl Prusa {
@ -56,26 +75,45 @@ impl Prusa {
fn get_info(&self) -> Result<Info, Error> { fn get_info(&self) -> Result<Info, Error> {
let api_target = "/api/printer"; let api_target = "/api/printer";
let resp = self.client.get(format!("http://{}{api_target}", self.ip_addr)) let resp = self
.header("X-Api-Key", &self.api_key) .client
.send()?; .get(format!("http://{}{api_target}", self.ip_addr))
.header("X-Api-Key", &self.api_key)
.send()?;
let text = resp.text()?; let text = resp.text()?;
// println!("{text}"); println!("{text}");
let info: Info = serde_json::from_str(&text)?; let info: Info = serde_json::from_str(&text)?;
// println!("{info:?}"); // println!("{info:?}");
Ok(info) Ok(info)
} }
fn get_status(&self) -> Result<Status, Error> {
let api_target = "/api/v1/status";
let resp = self
.client
.get(format!("http://{}{api_target}", self.ip_addr))
.header("X-Api-Key", &self.api_key)
.send()?;
let text = resp.text()?;
// println!("{text}");
let status: Status = serde_json::from_str(&text)?;
// println!("{info:?}");
// Ok(info)
Ok(status)
}
// TODO return this into a specific type // TODO return this into a specific type
fn get_storage_info(&self) -> Result<StorageInfo, Error> { fn get_storage_info(&self) -> Result<StorageInfo, Error> {
let api_target = "/api/v1/storage"; let api_target = "/api/v1/storage";
let resp = self.client.get(format!("http://{}{api_target}", self.ip_addr)) let resp = self
.client
.get(format!("http://{}{api_target}", self.ip_addr))
.header("X-Api-Key", &self.api_key) .header("X-Api-Key", &self.api_key)
.send()?; .send()?;
let text = resp.text()?; let text = resp.text()?;
// println!("{text}"); // println!("{text}");
let info: StorageInfo = serde_json::from_str(&text)?; let info: StorageInfo = serde_json::from_str(&text)?;
Ok(info) Ok(info)
} }
@ -86,7 +124,6 @@ impl Prusa {
// type: string // type: string
// format: binary // format: binary
// Need parameters // Need parameters
/* /*
parameters: parameters:
@ -127,7 +164,9 @@ impl Prusa {
// TODO: Allow storage selection // TODO: Allow storage selection
// For now, assume that we're using only USB: // For now, assume that we're using only USB:
let api_target = format!("/api/v1/files/usb/{uuid}.bgcode"); let api_target = format!("/api/v1/files/usb/{uuid}.bgcode");
let resp = self.client.put(format!("http://{}{api_target}", self.ip_addr)) let resp = self
.client
.put(format!("http://{}{api_target}", self.ip_addr))
.header("X-Api-Key", &self.api_key) .header("X-Api-Key", &self.api_key)
.header("Content-Type", "application/octet-stream") .header("Content-Type", "application/octet-stream")
.header("Content-Length", data.len()) .header("Content-Length", data.len())
@ -183,17 +222,18 @@ impl Prusa {
fn try_print_file(&self, id: &Uuid) -> Result<(), Error> { fn try_print_file(&self, id: &Uuid) -> Result<(), Error> {
// /api/v1/files/{storage}/{path} // /api/v1/files/{storage}/{path}
let api_target = format!("/api/v1/files/usb/{id}.bgcode"); let api_target = format!("/api/v1/files/usb/{id}.bgcode");
let resp = self.client.post(format!("http://{}{api_target}", self.ip_addr)) let resp = self
.client
.post(format!("http://{}{api_target}", self.ip_addr))
.header("X-Api-Key", &self.api_key) .header("X-Api-Key", &self.api_key)
.header("Content-Type", "application/octet-stream") .header("Content-Type", "application/octet-stream")
.send()?; .send()?;
let text = resp.text()?; let text = resp.text()?;
println!("{text}"); println!("{text}");
Ok(()) Ok(())
} }
// TODO: poorly named, should be something else so as not to confuse with print operations // TODO: poorly named, should be something else so as not to confuse with print operations
fn print_info(&self) -> Result<(), Error> { fn print_info(&self) -> Result<(), Error> {
let info = self.get_info()?; let info = self.get_info()?;
@ -230,6 +270,7 @@ struct Cli {
#[derive(Subcommand)] #[derive(Subcommand)]
enum Command { enum Command {
Info, Info,
Status,
Load { Load {
filepath: String, filepath: String,
#[arg(long)] #[arg(long)]
@ -263,7 +304,6 @@ pub enum Error {
JsonError(#[from] serde_json::Error), JsonError(#[from] serde_json::Error),
} }
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
let cli = Cli::parse(); let cli = Cli::parse();
let file_data = fs::read_to_string(cli.printer_config)?; let file_data = fs::read_to_string(cli.printer_config)?;
@ -277,19 +317,27 @@ fn main() -> Result<(), Error> {
Command::Info => { Command::Info => {
prusa.print_info()?; prusa.print_info()?;
prusa.print_storage_info()?; prusa.print_storage_info()?;
}, }
Command::Status => {
let status = prusa.get_status()?;
// println!("{status:?}");
println!("{}", serde_json::to_string(&status)?);
}
// Should generate UUID for the filename: // Should generate UUID for the filename:
Command::Load {filepath, print_immediately} => { Command::Load {
filepath,
print_immediately,
} => {
let uuid = prusa.try_load_file(&filepath)?; let uuid = prusa.try_load_file(&filepath)?;
if print_immediately { if print_immediately {
prusa.try_print_file(&uuid)?; prusa.try_print_file(&uuid)?;
} }
println!("Loaded as UUID:\n{uuid}"); println!("Loaded as UUID:\n{uuid}");
}, }
Command::Print {file_id} => prusa.try_print_file(&file_id)?, Command::Print { file_id } => prusa.try_print_file(&file_id)?,
} }
} }
_ => println!("Unrecognized printer type") _ => println!("Unrecognized printer type"),
} }
Ok(()) Ok(())