Skip to content

Commit a6e9360

Browse files
Make event messaging better; implement klippy_state
1 parent a6e28c4 commit a6e9360

13 files changed

Lines changed: 367 additions & 130 deletions

File tree

moonraker-rs/src/connector/read_deserialize.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,23 @@ impl<'de> Deserialize<'de> for JsonRpcNotification {
5151
struct NotificationHelper {
5252
jsonrpc: String,
5353
method: String,
54-
params: Vec<serde_json::Value>,
54+
params: Option<Vec<serde_json::Value>>,
5555
}
5656

57-
let mut helper = NotificationHelper::deserialize(deserializer)?;
57+
let helper = NotificationHelper::deserialize(deserializer)?;
5858

5959
let params = match helper.method.as_str() {
6060
"notify_status_update" => {
61-
let parsed_params = serde_json::from_value(helper.params[0].take())
61+
let parsed_params = serde_json::from_value(helper.params.unwrap()[0].take())
6262
.map_err(serde::de::Error::custom)?;
6363
MoonrakerEventParameters::NotifyStatusUpdate(parsed_params)
6464
}
6565
"notify_proc_stat_update" => {
66-
let parsed_params = serde_json::from_value(helper.params[0].take())
66+
let parsed_params = serde_json::from_value(helper.params.unwrap()[0].take())
6767
.map_err(serde::de::Error::custom)?;
6868
MoonrakerEventParameters::NotifyProcessStatisticsUpdate(parsed_params)
6969
}
70+
"notify_klippy_disconnected" => MoonrakerEventParameters::NotifyKlippyDisconnect,
7071
_ => return Err(serde::de::Error::custom("Unknown method")),
7172
};
7273

@@ -82,6 +83,7 @@ impl<'de> Deserialize<'de> for JsonRpcNotification {
8283
pub enum MoonrakerEventParameters {
8384
NotifyStatusUpdate(MoonrakerEventNotifyStatusUpdate),
8485
NotifyProcessStatisticsUpdate(MoonrakerNotifyProcStatUpdate),
86+
NotifyKlippyDisconnect,
8587
}
8688

8789
#[derive(Debug)]

moonraker-rs/src/connector/websocket_read.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ impl MoonrakerConnectionReadLoop {
9494
} {
9595
// TODO: Erorr handling
9696
eprintln!("Failed to process websocket event: {:?}", e);
97+
98+
if let Error::BreakError = e {
99+
#[cfg(debug_assertions)]
100+
println!("Breaking out of read loop");
101+
break;
102+
}
97103
}
98104
}
99105
}
@@ -152,6 +158,11 @@ impl MoonrakerConnectionReadLoop {
152158
}
153159
MoonrakerEventParameters::NotifyProcessStatisticsUpdate(proc_stat_update) => {
154160
self.inbound_sender.send(Arc::new(WebsocketEvent::MoonrakerEvent(MoonrakerEvent::NotifyProcessStatisticsUpdate(proc_stat_update)))).expect("Failed to internally send a moonraker process statistics update event");
161+
},
162+
MoonrakerEventParameters::NotifyKlippyDisconnect => {
163+
self.inbound_sender.send(Arc::new(WebsocketEvent::Disconnected)).expect("Failed to internally send a disconnect event");
164+
self.outbound_sender.send(Arc::new(OutboundMessage::EndLoop)).expect("Failed to internally send an endloop event");
165+
return Err(Error::BreakError);
155166
}
156167
}
157168
}

moonraker-rs/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ pub enum Error {
99
WebsocketWriteError(#[from] WebSocketError),
1010
#[error("Unknown error")]
1111
Unknown(String),
12+
#[error("Internally used")]
13+
BreakError,
1214
}

moonraker-rs/src/moonraker_connection.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use serde_json::Value;
1313
use std::error::Error;
1414
use std::fmt::Debug;
1515
use std::sync::Arc;
16+
use std::time::Duration;
1617
use tokio::io::{ReadHalf, WriteHalf};
1718
use tokio::net::TcpStream;
1819
use tokio::sync::broadcast::{Receiver, Sender};
@@ -75,7 +76,6 @@ pub struct MoonrakerConnection {
7576
impl MoonrakerConnection {
7677
pub fn new(host: &str, port: u16) -> Self {
7778
let host = format!("{}:{}", host, port);
78-
let url = format!("ws://{}/websocket", host);
7979

8080
let req = Request::builder()
8181
.method("GET")
@@ -173,6 +173,8 @@ impl MoonrakerConnection {
173173
}
174174
};
175175

176+
// TODO: Wait until Klippy is ready
177+
176178
// TOOD: Don't subscribe to objects we don't have a use for.
177179
let initial_objects = self
178180
.subscribe_to_printer_objects(object_list.objects.clone())
@@ -193,6 +195,7 @@ impl MoonrakerConnection {
193195

194196
reader_handle.await.unwrap();
195197
writer_handle.await.unwrap();
198+
sleep(Duration::from_secs(2)).await;
196199
}
197200
}
198201

moonraker-rs/src/printer_objects/webhooks.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::fmt::Display;
2+
13
use optional_struct::*;
24
use serde::Deserialize;
35

@@ -16,6 +18,18 @@ impl Default for KlippyState {
1618
}
1719
}
1820

21+
impl Display for KlippyState {
22+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23+
let state_str = match self {
24+
KlippyState::Ready => "Ready",
25+
KlippyState::Startup => "Startup",
26+
KlippyState::Error => "Error",
27+
KlippyState::Shutdown => "Shutdown",
28+
};
29+
write!(f, "{}", state_str)
30+
}
31+
}
32+
1933
#[optional_struct]
2034
#[derive(Debug, Deserialize, Clone)]
2135
pub struct Webhooks {

src/application_error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ pub enum ApplicationError {
66
IoError(#[from] std::io::Error),
77
#[error("Slint platform error")]
88
SlintFailure(#[from] slint::PlatformError),
9+
#[error("Event loop error")]
10+
EventLoopError(#[from] slint::EventLoopError),
911
#[error("Unknown application error")]
1012
Unknown(String),
1113
}

src/event_loop/event_loop.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use std::sync::Arc;
2+
3+
use moonraker_rs::{connector::websocket_read::{MoonrakerEvent, PrinterEvent}, moonraker_connection::{MoonrakerConnection, WebsocketEvent}};
4+
use slint::{ComponentHandle, Weak};
5+
6+
use crate::{application_error::ApplicationError, event_loop::{KlipperStateHandler, TemperatureDevicesHandler}, AppState, AppWindow};
7+
8+
pub struct EventLoop
9+
{
10+
pub ui_weak : Weak<AppWindow>,
11+
pub moonraker_connection : Arc<MoonrakerConnection>
12+
}
13+
14+
impl EventLoop
15+
{
16+
pub fn new(ui_weak : Weak<AppWindow>, moonraker_connection : Arc<MoonrakerConnection>) -> EventLoop
17+
{
18+
EventLoop { ui_weak: ui_weak, moonraker_connection: moonraker_connection }
19+
}
20+
21+
pub async fn event_loop(&mut self)
22+
{
23+
let mut receiver = self.moonraker_connection.get_listener();
24+
loop
25+
{
26+
match receiver.recv().await
27+
{
28+
Ok(message) =>
29+
{
30+
if let Err(e) = match &*message
31+
{
32+
WebsocketEvent::Connected => self.on_connected().await,
33+
WebsocketEvent::Disconnected => self.on_disconnected().await,
34+
WebsocketEvent::MoonrakerEvent(event) => self.on_event(event).await,
35+
_ => Ok(()),
36+
}
37+
{
38+
eprintln!("Error handling Moonraker message: {}", e);
39+
}
40+
},
41+
Err(e) =>
42+
{
43+
eprintln!("Error receiving message from Moonraker: {}", e);
44+
break;
45+
}
46+
}
47+
}
48+
}
49+
50+
async fn on_connected(&mut self) -> Result<(), ApplicationError>
51+
{
52+
self.ui_weak
53+
.upgrade_in_event_loop(move |ui| ui.global::<AppState>().set_moonraker_connected(true))?;
54+
55+
Ok(())
56+
}
57+
58+
async fn on_disconnected(&mut self) -> Result<(), ApplicationError>
59+
{
60+
self.ui_weak
61+
.upgrade_in_event_loop(move |ui| {
62+
ui.global::<AppState>().set_moonraker_connected(false);
63+
ui.global::<AppState>().set_klipper_state("Disconnected".into());
64+
ui.global::<AppState>().set_klipper_state_message("Disconnected".into());
65+
})?;
66+
67+
Ok(())
68+
}
69+
70+
async fn on_event(&mut self, moonraker_event : &MoonrakerEvent) -> Result<(), ApplicationError>
71+
{
72+
match moonraker_event
73+
{
74+
MoonrakerEvent::NotifyStatusUpdate(printer_event) => self.on_status_update(printer_event).await,
75+
_ => Ok(()),
76+
}
77+
}
78+
79+
async fn on_status_update(&mut self, printer_event : &PrinterEvent) -> Result<(), ApplicationError>
80+
{
81+
self.handle_temperature_devices_update(printer_event)?;
82+
self.handle_klipper_state_updates(printer_event)?;
83+
84+
Ok(())
85+
}
86+
}

src/event_loop/klipper_state.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use moonraker_rs::connector::websocket_read::PrinterEvent;
2+
use slint::{ComponentHandle, SharedString};
3+
4+
use crate::{application_error::ApplicationError, event_loop::EventLoop};
5+
6+
pub trait KlipperStateHandler {
7+
fn handle_klipper_state_updates(
8+
&mut self,
9+
printer_event: &PrinterEvent,
10+
) -> Result<(), ApplicationError>;
11+
}
12+
13+
impl KlipperStateHandler for EventLoop {
14+
fn handle_klipper_state_updates(
15+
&mut self,
16+
printer_event: &PrinterEvent,
17+
) -> Result<(), ApplicationError> {
18+
if let PrinterEvent::Webhooks(webhooks) = printer_event {
19+
let state = SharedString::from(webhooks.state.to_string());
20+
let state_message = SharedString::from(&webhooks.state_message);
21+
22+
self.ui_weak.upgrade_in_event_loop(move |ui| {
23+
ui.global::<crate::AppState>().set_klipper_state(state);
24+
ui.global::<crate::AppState>().set_klipper_state_message(state_message);
25+
})?;
26+
}
27+
28+
Ok(())
29+
}
30+
}

src/event_loop/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
pub mod event_loop;
2+
pub mod temperature_devices;
3+
pub mod klipper_state;
4+
5+
pub use event_loop::*;
6+
pub use temperature_devices::*;
7+
pub use klipper_state::*;
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use std::rc::Rc;
2+
3+
use moonraker_rs::connector::websocket_read::PrinterEvent;
4+
use slint::{ComponentHandle, Model, ModelRc, SharedString, VecModel};
5+
6+
use crate::{
7+
application_error::ApplicationError, event_loop::EventLoop, AppWindow, Heater, HeaterFan, TemperatureSensor, TemperatureSensors
8+
};
9+
10+
pub trait TemperatureDevicesHandler {
11+
fn handle_temperature_devices_update(
12+
&mut self,
13+
printer_event: &PrinterEvent,
14+
) -> Result<(), ApplicationError>;
15+
}
16+
17+
impl TemperatureDevicesHandler for EventLoop {
18+
fn handle_temperature_devices_update(
19+
&mut self,
20+
printer_event: &PrinterEvent,
21+
) -> Result<(), ApplicationError> {
22+
if let PrinterEvent::Extruder(extruder_event) = printer_event {
23+
let extruder = Heater {
24+
name: SharedString::from("extruder"),
25+
target: extruder_event.target as i32,
26+
temperature: extruder_event.temperature as i32,
27+
};
28+
29+
self.ui_weak
30+
.upgrade_in_event_loop(Box::new(move |ui: AppWindow| {
31+
ui.global::<TemperatureSensors>().set_extruder(extruder)
32+
}))?;
33+
}
34+
35+
if let PrinterEvent::HeaterBed(heater_bed_event) = printer_event {
36+
let bed = Heater {
37+
name: SharedString::from("heated_bed"),
38+
target: heater_bed_event.target as i32,
39+
temperature: heater_bed_event.temperature as i32,
40+
};
41+
42+
self.ui_weak.upgrade_in_event_loop(move |ui: AppWindow| {
43+
ui.global::<TemperatureSensors>().set_heated_bed(bed)
44+
})?;
45+
}
46+
47+
if let PrinterEvent::TemperatureSensor(temperature_sensor_event) = printer_event {
48+
let sensor_event = TemperatureSensor {
49+
name: SharedString::from(&temperature_sensor_event.name),
50+
temperature: temperature_sensor_event.sensor.temperature as i32,
51+
};
52+
53+
self.ui_weak
54+
.upgrade_in_event_loop(move |ui| {
55+
let temperature_sensors =
56+
ui.global::<TemperatureSensors>().get_temperature_sensors();
57+
let current_sensors = temperature_sensors
58+
.as_any()
59+
.downcast_ref::<VecModel<TemperatureSensor>>();
60+
61+
let mut entries = match &current_sensors {
62+
Some(model) => model.iter().collect::<Vec<TemperatureSensor>>(),
63+
None => vec![],
64+
};
65+
66+
let index = entries
67+
.iter()
68+
.position(|sensor| sensor.name == sensor_event.name);
69+
70+
match index {
71+
Some(index) => entries[index].temperature = sensor_event.temperature as i32,
72+
None => entries.push(sensor_event),
73+
}
74+
75+
ui.global::<TemperatureSensors>()
76+
.set_temperature_sensors(ModelRc::new(Rc::new(VecModel::from(entries))));
77+
})?;
78+
}
79+
80+
if let PrinterEvent::TemperatureFan(temperature_fan_event) = printer_event {
81+
let sensor_event = HeaterFan {
82+
heater: Heater {
83+
name: SharedString::from(&temperature_fan_event.name),
84+
temperature: temperature_fan_event.fan.temperature as i32,
85+
target: temperature_fan_event.fan.target as i32,
86+
},
87+
speed: temperature_fan_event.fan.speed,
88+
};
89+
90+
self.ui_weak
91+
.upgrade_in_event_loop(move |ui| {
92+
let heater_fans =
93+
ui.global::<TemperatureSensors>().get_heater_fans();
94+
let current_sensors = heater_fans
95+
.as_any()
96+
.downcast_ref::<VecModel<HeaterFan>>();
97+
98+
let mut entries = match &current_sensors {
99+
Some(model) => model.iter().collect::<Vec<HeaterFan>>(),
100+
None => vec![],
101+
};
102+
103+
let index = entries
104+
.iter()
105+
.position(|sensor| sensor.heater.name == sensor_event.heater.name);
106+
107+
match index {
108+
Some(index) => {
109+
entries[index].heater.temperature = sensor_event.heater.temperature;
110+
entries[index].heater.target = sensor_event.heater.target;
111+
entries[index].speed = sensor_event.speed;
112+
},
113+
None => entries.push(sensor_event),
114+
}
115+
116+
ui.global::<TemperatureSensors>()
117+
.set_heater_fans(ModelRc::new(Rc::new(VecModel::from(entries))));
118+
})?;
119+
}
120+
121+
Ok(())
122+
}
123+
}

0 commit comments

Comments
 (0)